mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into agpl_next
This commit is contained in:
commit
123f766935
|
@ -30,7 +30,7 @@ endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
|||
########################################################################
|
||||
# Project setup
|
||||
########################################################################
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project( SRSRAN )
|
||||
message( STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} )
|
||||
message( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} )
|
||||
|
@ -69,6 +69,7 @@ option(DISABLE_SIMD "Disable SIMD instructions" OFF)
|
|||
option(AUTO_DETECT_ISA "Autodetect supported ISA extensions" ON)
|
||||
|
||||
option(ENABLE_GUI "Enable GUI (using srsGUI)" ON)
|
||||
option(ENABLE_RF_PLUGINS "Enable RF plugins" ON)
|
||||
option(ENABLE_UHD "Enable UHD" ON)
|
||||
option(ENABLE_BLADERF "Enable BladeRF" ON)
|
||||
option(ENABLE_SOAPYSDR "Enable SoapySDR" ON)
|
||||
|
@ -509,8 +510,12 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
endif ()
|
||||
|
||||
if (ENABLE_ASAN)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||
# Note: When using ASAN, we need to ensure the use of RPATH instead of RUNPATH via "-Wl,--disable-new-dtags"
|
||||
# While RPATH is default, some systems (e.g. Ubuntu 18.04 and 20.04) use RUNPATH by default, which is non-transitive.
|
||||
# Since ASAN intercepts dlopen(), by which it replaces the dynamic string token "$ORIGIN" to its own location,
|
||||
# the RF plugins won't be found by "libsrsran_rf.so" when using ASAN + RUNPATH in the top-level executable.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -Wl,--disable-new-dtags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -Wl,--disable-new-dtags")
|
||||
endif (ENABLE_ASAN)
|
||||
|
||||
if (ENABLE_TSAN)
|
||||
|
|
|
@ -28,31 +28,45 @@
|
|||
find_path(MKL_INCLUDE_DIR
|
||||
NAMES mkl.h
|
||||
HINTS $ENV{MKL_DIR}/include
|
||||
/opt/intel/oneapi/mkl/latest/include
|
||||
/opt/intel/mkl/include
|
||||
/usr/include/mkl
|
||||
PATHS)
|
||||
|
||||
find_path(MKL_FFTW_INCLUDE_DIR
|
||||
NAMES fftw3.h
|
||||
HINTS $ENV{MKL_DIR}/include/fftw
|
||||
/opt/intel/oneapi/mkl/latest/include/fftw
|
||||
/opt/intel/mkl/include/fftw
|
||||
/usr/include/mkl/fftw
|
||||
PATHS)
|
||||
|
||||
find_library(MKL_LIBRARIES
|
||||
NAMES mkl_rt
|
||||
HINTS $ENV{MKL_DIR}/lib/intel64
|
||||
/opt/intel/oneapi/mkl/latest/lib/intel64
|
||||
/opt/intel/mkl/lib/intel64
|
||||
PATHS)
|
||||
|
||||
find_library(MKL_CORE
|
||||
NAMES libmkl_core.a
|
||||
HINTS $ENV{MKL_DIR}/lib/intel64
|
||||
/opt/intel/oneapi/mkl/latest/lib/intel64/
|
||||
/opt/intel/mkl/lib/intel64
|
||||
PATHS)
|
||||
|
||||
find_library(MKL_ILP
|
||||
NAMES libmkl_intel_ilp64.a
|
||||
HINTS $ENV{MKL_DIR}/lib/intel64
|
||||
/opt/intel/oneapi/mkl/latest/lib/intel64/
|
||||
/opt/intel/mkl/lib/intel64
|
||||
PATHS)
|
||||
|
||||
find_library(MKL_SEQ
|
||||
NAMES libmkl_sequential.a
|
||||
HINTS $ENV{MKL_DIR}/lib/intel64
|
||||
/opt/intel/oneapi/mkl/latest/lib/intel64/
|
||||
/opt/intel/mkl/lib/intel64
|
||||
PATHS)
|
||||
|
||||
set(MKL_STATIC_LIBRARIES -Wl,--start-group ${MKL_CORE} ${MKL_ILP} ${MKL_SEQ} -Wl,--end-group -lpthread -lm -ldl)
|
||||
|
@ -61,7 +75,7 @@ set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} ${MKL_FFTW_INCLUDE_DIR})
|
|||
include(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(mkl DEFAULT_MSG
|
||||
find_package_handle_standard_args(MKL DEFAULT_MSG
|
||||
MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ MKL_INCLUDE_DIRS)
|
||||
|
||||
if(MKL_FOUND)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
INCLUDE(FindPkgConfig)
|
||||
FIND_PACKAGE(PkgConfig REQUIRED)
|
||||
#PKG_CHECK_MODULES(SKIQ SKIQ)
|
||||
IF(NOT SKIQ_FOUND)
|
||||
|
||||
|
@ -26,7 +26,7 @@ FIND_PATH(
|
|||
SKIQ_INCLUDE_DIRS
|
||||
NAMES sidekiq_api.h
|
||||
HINTS $ENV{SKIQ_DIR}/inc
|
||||
$ENV{SKIQ_DIR}/sidekiq_core/inc
|
||||
$ENV{SKIQ_DIR}/sidekiq_core/inc
|
||||
PATHS /usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
|
|
@ -23,11 +23,11 @@ if(NOT SOAPYSDR_FOUND)
|
|||
pkg_check_modules (SOAPYSDR_PKG SoapySDR)
|
||||
|
||||
find_path(SOAPYSDR_INCLUDE_DIRS
|
||||
NAMES Device.h
|
||||
NAMES SoapySDR/Device.h
|
||||
HINTS $ENV{SOAPY_DIR}/include
|
||||
PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS}
|
||||
/usr/include/SoapySDR
|
||||
/usr/local/include/SoapySDR
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(SOAPYSDR_LIBRARIES
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
|
|
|
@ -66,7 +66,7 @@ endif(SRSGUI_FOUND)
|
|||
|
||||
if (ZEROMQ_FOUND)
|
||||
add_executable(zmq_remote_rx zmq_remote_rx.c)
|
||||
target_link_libraries(zmq_remote_rx srsran_phy srsran_rf)
|
||||
target_link_libraries(zmq_remote_rx srsran_phy srsran_rf ${ZEROMQ_LIBRARIES})
|
||||
endif (ZEROMQ_FOUND)
|
||||
|
||||
#################################################################
|
||||
|
|
|
@ -86,10 +86,6 @@ static bool enable_256qam = false;
|
|||
static float output_file_snr = +INFINITY;
|
||||
static bool use_standard_lte_rate = false;
|
||||
|
||||
// CFR type test args
|
||||
static char cfr_manual_str[] = "manual";
|
||||
static char cfr_auto_cma_str[] = "auto_cma";
|
||||
static char cfr_auto_ema_str[] = "auto_ema";
|
||||
|
||||
// CFR runtime control flags
|
||||
static bool cfr_thr_inc = false;
|
||||
|
@ -105,7 +101,7 @@ typedef struct {
|
|||
} cfr_args_t;
|
||||
|
||||
static cfr_args_t cfr_args = {.enable = 0,
|
||||
.mode = cfr_manual_str,
|
||||
.mode = "manual",
|
||||
.manual_thres = 1.0f,
|
||||
.strength = 1.0f,
|
||||
.auto_target_papr = 8.0f,
|
||||
|
@ -301,14 +297,9 @@ static int parse_cfr_args()
|
|||
cfr_config.alpha = cfr_args.strength;
|
||||
cfr_config.ema_alpha = cfr_args.ema_alpha;
|
||||
|
||||
if (!strcmp(cfr_args.mode, cfr_manual_str)) {
|
||||
cfr_config.cfr_mode = SRSRAN_CFR_THR_MANUAL;
|
||||
} else if (!strcmp(cfr_args.mode, cfr_auto_cma_str)) {
|
||||
cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_CMA;
|
||||
} else if (!strcmp(cfr_args.mode, cfr_auto_ema_str)) {
|
||||
cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_EMA;
|
||||
} else {
|
||||
ERROR("CFR mode is not recognised");
|
||||
cfr_config.cfr_mode = srsran_cfr_str2mode(cfr_args.mode);
|
||||
if (cfr_config.cfr_mode == SRSRAN_CFR_THR_INVALID) {
|
||||
ERROR("CFR mode not recognised");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ int main(int argc, char** argv)
|
|||
cf_t* equalized_sf_buffer = srsran_vec_malloc(sizeof(cf_t) * sf_n_re);
|
||||
|
||||
// RX
|
||||
srsran_ofdm_t fft[SRSRAN_MAX_PORTS];
|
||||
srsran_ofdm_t fft[SRSRAN_MAX_PORTS] = {};
|
||||
srsran_ofdm_cfg_t ofdm_cfg = {};
|
||||
ofdm_cfg.nof_prb = cell_sl.nof_prb;
|
||||
ofdm_cfg.cp = SRSRAN_CP_NORM;
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<registration_type_type_, 3> registration_type_type;
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
|||
follow_on_request_pending = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<follow_on_request_bit_type_, 1> follow_on_request_bit_type;
|
||||
|
||||
|
@ -83,7 +83,7 @@ public:
|
|||
mapped_security_context = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<security_context_flag_type_, 1> security_context_flag_type;
|
||||
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
no_key_is_available_or_reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<nas_key_set_identifier_type_, 3> nas_key_set_identifier_type;
|
||||
|
||||
|
@ -122,7 +122,7 @@ public:
|
|||
eui_64 = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<identity_types_, 3> identity_types;
|
||||
|
||||
|
@ -140,7 +140,7 @@ public:
|
|||
gli = 0b100,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<supi_format_type_, 3> supi_format_type;
|
||||
|
||||
|
@ -151,7 +151,7 @@ public:
|
|||
ecies_scheme_profile_b = 0b0010,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<protection_scheme_id_type_, 4> protection_scheme_id_type;
|
||||
|
||||
|
@ -424,7 +424,7 @@ public:
|
|||
sst_sd_mapped_hplmn_sst_and_mapped_hplmn_sd = 0b00001000,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<SST_type_, 8> SST_type;
|
||||
|
||||
|
@ -655,7 +655,7 @@ public:
|
|||
data_centric = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<UE_usage_setting_type_, 1> UE_usage_setting_type;
|
||||
|
||||
|
@ -680,7 +680,7 @@ public:
|
|||
drx_cycle_parameter_t_256 = 0b0100,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<drx_value_type_, 4> drx_value_type;
|
||||
|
||||
|
@ -746,7 +746,7 @@ public:
|
|||
multiple_payloads = 0b1111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Payload_container_type_type_, 4> Payload_container_type_type;
|
||||
|
||||
|
@ -793,7 +793,7 @@ public:
|
|||
sms_over_nas_supported = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<SMS_requested_type_, 1> SMS_requested_type;
|
||||
|
||||
|
@ -803,7 +803,7 @@ public:
|
|||
ue_radio_capability_update_needed = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<NG_RAN_RCU_type_, 1> NG_RAN_RCU_type;
|
||||
|
||||
|
@ -815,7 +815,7 @@ public:
|
|||
reserved = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<PNB_5GS_CIoT_type_, 2> PNB_5GS_CIoT_type;
|
||||
|
||||
|
@ -827,7 +827,7 @@ public:
|
|||
reserved = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<PNB_EPS_CIoT_type_, 2> PNB_EPS_CIoT_type;
|
||||
|
||||
|
@ -925,7 +925,7 @@ public:
|
|||
seconds_20 = 0b1111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Paging_Time_Window_type_, 4> Paging_Time_Window_type;
|
||||
|
||||
|
@ -949,7 +949,7 @@ public:
|
|||
second_20_48 = 0b1111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<eDRX_value_type_, 4> eDRX_value_type;
|
||||
|
||||
|
@ -978,7 +978,7 @@ public:
|
|||
value_indicates_that_the_timer_is_deactivated = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Unit_type_, 3> Unit_type;
|
||||
|
||||
|
@ -1062,7 +1062,7 @@ public:
|
|||
drx_cycle_parameter_t_1024 = 0b0111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<nb_n1_mode_drx_value_type_, 4> nb_n1_mode_drx_value_type;
|
||||
|
||||
|
@ -1084,7 +1084,7 @@ public:
|
|||
registered_for_emergency_services = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Emergency_registered_type_, 1> Emergency_registered_type;
|
||||
|
||||
|
@ -1094,7 +1094,7 @@ public:
|
|||
nssaa_is_to_be_performed = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<NSSAA_to_be_performed_type_, 1> NSSAA_to_be_performed_type;
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ public:
|
|||
sms_over_nas_allowed = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<SMS_allowed_type_, 1> SMS_allowed_type;
|
||||
|
||||
|
@ -1116,7 +1116,7 @@ public:
|
|||
reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<registration_result_type_, 3> registration_result_type;
|
||||
|
||||
|
@ -1154,7 +1154,7 @@ public:
|
|||
reserved = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<type_of_list_type_, 2> type_of_list_type;
|
||||
|
||||
|
@ -1307,7 +1307,7 @@ public:
|
|||
nssai_inclusion_mode_d = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<NSSAI_inclusion_mode_type_, 2> NSSAI_inclusion_mode_type;
|
||||
|
||||
|
@ -1351,7 +1351,7 @@ public:
|
|||
network_assigned_ue_radio_capability_i_ds_deletion_requested = 0b001,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Deletion_request_type_, 3> Deletion_request_type;
|
||||
|
||||
|
@ -1447,7 +1447,7 @@ public:
|
|||
protocol_error_unspecified = 0b01101111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<cause_5gmm_type_, 8> cause_5gmm_type;
|
||||
|
||||
|
@ -1469,7 +1469,7 @@ public:
|
|||
switch_off = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<switch_off_type_, 1> switch_off_type;
|
||||
|
||||
|
@ -1479,7 +1479,7 @@ public:
|
|||
re_registration_required = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<re_registration_required_type_, 1> re_registration_required_type;
|
||||
|
||||
|
@ -1490,7 +1490,7 @@ public:
|
|||
access_3_gpp_and_non_3_gpp_access = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<access_type_type_, 2> access_type_type;
|
||||
|
||||
|
@ -1535,7 +1535,7 @@ public:
|
|||
unused_shall_be_interpreted_as_data_2 = 0b1011,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Service_type_value_type_, 4> Service_type_value_type;
|
||||
|
||||
|
@ -1559,7 +1559,7 @@ public:
|
|||
emergency_services_fallback = 0b100,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<control_plane_service_type_value_type_, 3> control_plane_service_type_value_type;
|
||||
|
||||
|
@ -1624,7 +1624,7 @@ public:
|
|||
reserved = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<value_type_, 3> value_type;
|
||||
|
||||
|
@ -1658,7 +1658,7 @@ public:
|
|||
release_of_n1_nas_signalling_connection_not_required = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<SCMR_type_, 1> SCMR_type;
|
||||
|
||||
|
@ -1745,7 +1745,7 @@ public:
|
|||
eui_64 = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<identity_types_, 3> identity_types;
|
||||
|
||||
|
@ -1773,7 +1773,7 @@ public:
|
|||
ia7_5g = 0b0111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<integrity_protection_algorithm_type_, 4> integrity_protection_algorithm_type;
|
||||
|
||||
|
@ -1789,7 +1789,7 @@ public:
|
|||
ea7_5g = 0b0111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<ciphering_algorithm_type_, 4> ciphering_algorithm_type;
|
||||
|
||||
|
@ -1813,7 +1813,7 @@ public:
|
|||
imeisv_requested = 0b001,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<imeisv_request_type_, 3> imeisv_request_type;
|
||||
|
||||
|
@ -1841,7 +1841,7 @@ public:
|
|||
eia7 = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<integrity_protection_algorithm_type_, 3> integrity_protection_algorithm_type;
|
||||
|
||||
|
@ -1857,7 +1857,7 @@ public:
|
|||
eea7 = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<ciphering_algorithm_type_, 3> ciphering_algorithm_type;
|
||||
|
||||
|
@ -1943,7 +1943,7 @@ public:
|
|||
non_3_gpp_access = 0b10,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Access_type_value_type_, 2> Access_type_value_type;
|
||||
|
||||
|
@ -1982,7 +1982,7 @@ public:
|
|||
reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Request_type_value_type_, 3> Request_type_value_type;
|
||||
|
||||
|
@ -2015,7 +2015,7 @@ public:
|
|||
ma_pdu_session_network_upgrade_is_allowed = 0b0001,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<MA_PDU_session_information_value_type_, 4> MA_PDU_session_information_value_type;
|
||||
|
||||
|
@ -2040,7 +2040,7 @@ public:
|
|||
reserved = 0b11,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Downlink_data_expected_type_, 2> Downlink_data_expected_type;
|
||||
|
||||
|
@ -2064,7 +2064,7 @@ public:
|
|||
full_data_rate = 0b11111111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<max_data_rate_UPIP_uplink_type_, 8> max_data_rate_UPIP_uplink_type;
|
||||
|
||||
|
@ -2075,7 +2075,7 @@ public:
|
|||
full_data_rate = 0b11111111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<max_data_rate_UPIP_downlink_type_, 8> max_data_rate_UPIP_downlink_type;
|
||||
|
||||
|
@ -2102,7 +2102,7 @@ public:
|
|||
reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<PDU_session_type_value_type_, 3> PDU_session_type_value_type;
|
||||
|
||||
|
@ -2129,7 +2129,7 @@ public:
|
|||
reserved = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<SSC_mode_value_type_, 3> SSC_mode_value_type;
|
||||
|
||||
|
@ -2254,7 +2254,7 @@ public:
|
|||
bits_15 = 0b10,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<CID_Length_type_, 2> CID_Length_type;
|
||||
|
||||
|
@ -2277,7 +2277,7 @@ public:
|
|||
ipv4v6 = 0b011,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<PDU_session_type_value_type_, 3> PDU_session_type_value_type;
|
||||
|
||||
|
@ -2340,7 +2340,7 @@ public:
|
|||
inc_by_256_pbps = 0b00011001,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<unit_session_AMBR_type_, 8> unit_session_AMBR_type;
|
||||
|
||||
|
@ -2430,7 +2430,7 @@ public:
|
|||
value_indicates_that_the_timer_is_deactivated = 0b111,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<Unit_type_, 3> Unit_type;
|
||||
|
||||
|
@ -2485,7 +2485,7 @@ public:
|
|||
ethernet_pdn_type_in_s1_mode_supported = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<EPT_S1_type_, 1> EPT_S1_type;
|
||||
|
||||
|
@ -2557,7 +2557,7 @@ public:
|
|||
the_back_off_timer_is_applied_in_all_plm_ns = 0b1,
|
||||
|
||||
} value;
|
||||
const char* to_string();
|
||||
const char* to_string() const;
|
||||
};
|
||||
typedef nas_enumerated<abo_type_, 1> abo_type;
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ bool make_phy_tdd_cfg(const srsran_duplex_config_nr_t& srsran_duplex_config
|
|||
bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg,
|
||||
srsran_harq_ack_cfg_hl_t* srsran_ue_dl_nr_harq_ack_cfg);
|
||||
bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset);
|
||||
void make_phy_search_space0_cfg(srsran_search_space_t* in_srsran_search_space);
|
||||
bool make_phy_search_space_cfg(const asn1::rrc_nr::search_space_s& search_space,
|
||||
srsran_search_space_t* srsran_search_space);
|
||||
bool make_phy_csi_report(const asn1::rrc_nr::csi_report_cfg_s& csi_report_cfg,
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
srsran::srsran_rat_t rat;
|
||||
uint32_t lcid;
|
||||
uint32_t eps_bearer_id;
|
||||
uint32_t five_qi = 0;
|
||||
bool is_valid() const { return rat != srsran_rat_t::nulltype; }
|
||||
};
|
||||
static const radio_bearer_t invalid_rb;
|
||||
|
@ -59,9 +60,11 @@ public:
|
|||
|
||||
bool has_active_radio_bearer(uint32_t eps_bearer_id);
|
||||
|
||||
radio_bearer_t get_radio_bearer(uint32_t eps_bearer_id);
|
||||
radio_bearer_t get_radio_bearer(uint32_t eps_bearer_id) const;
|
||||
|
||||
radio_bearer_t get_eps_bearer_id_for_lcid(uint32_t lcid);
|
||||
radio_bearer_t get_eps_bearer_id_for_lcid(uint32_t lcid) const;
|
||||
|
||||
bool set_five_qi(uint32_t eps_bearer_id, uint16_t five_qi);
|
||||
|
||||
private:
|
||||
using eps_rb_map_t = std::map<uint32_t, radio_bearer_t>;
|
||||
|
@ -156,7 +159,8 @@ public:
|
|||
void rem_user(uint16_t rnti);
|
||||
bool has_active_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id);
|
||||
radio_bearer_t get_radio_bearer(uint16_t rnti, uint32_t eps_bearer_id);
|
||||
radio_bearer_t get_lcid_bearer(uint16_t rnti, uint32_t lcid);
|
||||
radio_bearer_t get_lcid_bearer(uint16_t rnti, uint32_t lcid) const;
|
||||
bool set_five_qi(uint16_t rnti, uint32_t eps_bearer_id, uint16_t five_qi);
|
||||
|
||||
private:
|
||||
srslog::basic_logger& logger;
|
||||
|
@ -166,4 +170,4 @@ private:
|
|||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSRAN_BEARER_MANAGER_H
|
||||
#endif // SRSRAN_BEARER_MANAGER_H
|
||||
|
|
|
@ -89,7 +89,7 @@ inline const char* enum_to_text(const char* const array[], uint32_t nof_types, u
|
|||
}
|
||||
|
||||
template <class ItemType>
|
||||
ItemType enum_to_number(ItemType* array, uint32_t nof_types, uint32_t enum_val)
|
||||
constexpr ItemType enum_to_number(ItemType* array, uint32_t nof_types, uint32_t enum_val)
|
||||
{
|
||||
return enum_val >= nof_types ? -1 : array[enum_val];
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ struct phy_cfg_nr_t {
|
|||
srsran_harq_ack_cfg_hl_t harq_ack = {};
|
||||
srsran_csi_hl_cfg_t csi = {};
|
||||
srsran_carrier_nr_t carrier = {};
|
||||
ssb_cfg_t ssb;
|
||||
ssb_cfg_t ssb = {};
|
||||
uint32_t t_offset = 0; ///< n-TimingAdvanceOffset
|
||||
|
||||
phy_cfg_nr_t() {}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ struct meas_cell_cfg_t {
|
|||
asn1::rrc::q_offset_range_e cell_individual_offset;
|
||||
uint32_t allowed_meas_bw;
|
||||
bool direct_forward_path_available;
|
||||
int tac;
|
||||
};
|
||||
|
||||
// neigh measurement Cell info
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
*/
|
||||
virtual bool send_ho_required(uint16_t rnti,
|
||||
uint32_t target_eci,
|
||||
uint16_t target_tac,
|
||||
srsran::plmn_id_t target_plmn,
|
||||
srsran::span<uint32_t> fwd_erabs,
|
||||
srsran::unique_byte_buffer_t rrc_container,
|
||||
|
|
|
@ -39,6 +39,7 @@ class rrc_nr_interface_rrc
|
|||
public:
|
||||
struct sgnb_addition_req_params_t {
|
||||
uint32_t eps_bearer_id;
|
||||
uint32_t five_qi;
|
||||
// add configuration check
|
||||
// E-RAB Parameters, Tunnel address (IP address, TEID)
|
||||
// QCI, security, etc
|
||||
|
|
|
@ -29,17 +29,20 @@ namespace srsenb {
|
|||
class rrc_interface_ngap_nr
|
||||
{
|
||||
public:
|
||||
virtual int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key) = 0;
|
||||
virtual int ue_set_bitrates(uint16_t rnti, const asn1::ngap::ue_aggregate_maximum_bit_rate_s& rates) = 0;
|
||||
virtual int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap::ue_aggregate_maximum_bit_rate_s& rates) = 0;
|
||||
virtual int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap::ue_security_cap_s& caps) = 0;
|
||||
virtual int start_security_mode_procedure(uint16_t rnti, srsran::unique_byte_buffer_t nas_pdu) = 0;
|
||||
virtual int
|
||||
establish_rrc_bearer(uint16_t rnti, uint16_t pdu_session_id, srsran::const_byte_span nas_pdu, uint32_t lcid) = 0;
|
||||
virtual int allocate_lcid(uint16_t rnti) = 0;
|
||||
virtual int release_bearers(uint16_t rnti) = 0;
|
||||
virtual void release_user(uint16_t rnti) = 0;
|
||||
virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0;
|
||||
virtual int ue_set_security_cfg_key(uint16_t rnti, const asn1::fixed_bitstring<256, false, true>& key) = 0;
|
||||
virtual int ue_set_bitrates(uint16_t rnti, const asn1::ngap::ue_aggregate_maximum_bit_rate_s& rates) = 0;
|
||||
virtual int set_aggregate_max_bitrate(uint16_t rnti, const asn1::ngap::ue_aggregate_maximum_bit_rate_s& rates) = 0;
|
||||
virtual int ue_set_security_cfg_capabilities(uint16_t rnti, const asn1::ngap::ue_security_cap_s& caps) = 0;
|
||||
virtual int start_security_mode_procedure(uint16_t rnti, srsran::unique_byte_buffer_t nas_pdu) = 0;
|
||||
virtual int establish_rrc_bearer(uint16_t rnti,
|
||||
uint16_t pdu_session_id,
|
||||
srsran::const_byte_span nas_pdu,
|
||||
uint32_t lcid,
|
||||
uint32_t five_qi) = 0;
|
||||
virtual int allocate_lcid(uint16_t rnti) = 0;
|
||||
virtual int release_bearers(uint16_t rnti) = 0;
|
||||
virtual void release_user(uint16_t rnti) = 0;
|
||||
virtual void write_dl_info(uint16_t rnti, srsran::unique_byte_buffer_t sdu) = 0;
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
|
|
@ -73,11 +73,28 @@ inline std::string to_string(const rlc_am_nr_sn_size_t& sn_size)
|
|||
constexpr static const char* options[] = {"12 bits", "18 bits"};
|
||||
return enum_to_text(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
|
||||
}
|
||||
inline uint16_t to_number(const rlc_am_nr_sn_size_t& sn_size)
|
||||
constexpr uint16_t to_number(const rlc_am_nr_sn_size_t& sn_size)
|
||||
{
|
||||
constexpr static uint16_t options[] = {12, 18};
|
||||
constexpr uint16_t options[] = {12, 18};
|
||||
return enum_to_number(options, (uint32_t)rlc_mode_t::nulltype, (uint32_t)sn_size);
|
||||
}
|
||||
/**
|
||||
* @brief Value range of the serial numbers
|
||||
* @param sn_size Length of the serial number field in bits
|
||||
* @return cardianlity
|
||||
*/
|
||||
constexpr uint32_t cardinality(const rlc_am_nr_sn_size_t& sn_size)
|
||||
{
|
||||
return (1 << to_number(sn_size));
|
||||
}
|
||||
/****************************************************************************
|
||||
* Tx constants
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.2
|
||||
***************************************************************************/
|
||||
constexpr uint32_t am_window_size(const rlc_am_nr_sn_size_t& sn_size)
|
||||
{
|
||||
return cardinality(sn_size) / 2;
|
||||
}
|
||||
|
||||
struct rlc_am_config_t {
|
||||
/****************************************************************************
|
||||
|
@ -228,14 +245,25 @@ public:
|
|||
rlc_cnfg.am.t_poll_retx = 5;
|
||||
return rlc_cnfg;
|
||||
}
|
||||
static rlc_config_t default_rlc_am_nr_config()
|
||||
static rlc_config_t default_rlc_am_nr_config(uint32_t sn_size = 12)
|
||||
{
|
||||
rlc_config_t rlc_cnfg = {};
|
||||
rlc_cnfg.rat = srsran_rat_t::nr;
|
||||
rlc_cnfg.rlc_mode = rlc_mode_t::am;
|
||||
rlc_config_t rlc_cnfg = {};
|
||||
rlc_cnfg.rat = srsran_rat_t::nr;
|
||||
rlc_cnfg.rlc_mode = rlc_mode_t::am;
|
||||
if (sn_size == 12) {
|
||||
rlc_cnfg.am_nr.tx_sn_field_length = srsran::rlc_am_nr_sn_size_t::size12bits;
|
||||
rlc_cnfg.am_nr.rx_sn_field_length = srsran::rlc_am_nr_sn_size_t::size12bits;
|
||||
} else if (sn_size == 18) {
|
||||
rlc_cnfg.am_nr.tx_sn_field_length = srsran::rlc_am_nr_sn_size_t::size18bits;
|
||||
rlc_cnfg.am_nr.rx_sn_field_length = srsran::rlc_am_nr_sn_size_t::size18bits;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
rlc_cnfg.am_nr.t_status_prohibit = 8;
|
||||
rlc_cnfg.am_nr.max_retx_thresh = 4;
|
||||
rlc_cnfg.am_nr.t_reassembly = 35;
|
||||
rlc_cnfg.am_nr.poll_pdu = 4;
|
||||
rlc_cnfg.am_nr.t_poll_retx = 45;
|
||||
return rlc_cnfg;
|
||||
}
|
||||
static rlc_config_t default_rlc_um_nr_config(uint32_t sn_size = 6)
|
||||
|
|
|
@ -206,6 +206,9 @@ public:
|
|||
|
||||
// RRC informs MAC about new UE identity for contention-free RA
|
||||
virtual bool set_crnti(const uint16_t crnti) = 0;
|
||||
|
||||
// RRC informs MAC to start/stop search for BCCH messages
|
||||
virtual void bcch_search(bool enabled) = 0;
|
||||
};
|
||||
|
||||
struct phy_args_nr_t {
|
||||
|
@ -264,6 +267,12 @@ public:
|
|||
const float preamble_received_target_power,
|
||||
const float ta_base_sec = 0.0f) = 0;
|
||||
|
||||
/// Apply TA command after RAR
|
||||
virtual void set_timeadv_rar(uint32_t tti, uint32_t ta_cmd) = 0;
|
||||
|
||||
/// Apply TA command after MAC CE
|
||||
virtual void set_timeadv(uint32_t tti, uint32_t ta_cmd) = 0;
|
||||
|
||||
/**
|
||||
* @brief Query PHY if there is a valid PUCCH SR resource configured for a given SR identifier
|
||||
* @param sr_id SR identifier
|
||||
|
|
|
@ -68,6 +68,13 @@ public:
|
|||
virtual bool is_lcid_enabled(uint32_t lcid) = 0;
|
||||
};
|
||||
|
||||
// SDAP interface
|
||||
class pdcp_interface_sdap_nr
|
||||
{
|
||||
public:
|
||||
virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) = 0;
|
||||
};
|
||||
|
||||
// STACK interface for GW (based on EPS-bearer IDs)
|
||||
class stack_interface_gw
|
||||
{
|
||||
|
|
|
@ -35,6 +35,15 @@
|
|||
|
||||
namespace srsue {
|
||||
|
||||
struct cfr_args_t {
|
||||
bool enable = false;
|
||||
srsran_cfr_mode_t mode = SRSRAN_CFR_THR_MANUAL;
|
||||
float manual_thres = 2.0f;
|
||||
float strength = 1.0f;
|
||||
float auto_target_papr = 7.0f;
|
||||
float ema_alpha = 1.0f / (float)SRSRAN_CP_NORM_NSYMB;
|
||||
};
|
||||
|
||||
struct phy_args_t {
|
||||
std::string type = "lte";
|
||||
srsran::phy_log_args_t log;
|
||||
|
@ -105,6 +114,8 @@ struct phy_args_t {
|
|||
|
||||
srsran::channel::args_t dl_channel_args;
|
||||
srsran::channel::args_t ul_channel_args;
|
||||
|
||||
cfr_args_t cfr_args; ///< Stores user-defined CFR configuration
|
||||
};
|
||||
|
||||
/* RAT agnostic Interface MAC -> PHY */
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* File: ue_sdap_interfaces.h
|
||||
* Description: Abstract base class interfaces for SDAP layer
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SRSRAN_UE_SDAP_INTERFACES_H
|
||||
#define SRSRAN_UE_SDAP_INTERFACES_H
|
||||
|
||||
/*****************************
|
||||
* SDAP INTERFACES
|
||||
****************************/
|
||||
class sdap_interface_pdcp_nr
|
||||
{
|
||||
public:
|
||||
virtual void write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) = 0;
|
||||
};
|
||||
class sdap_interface_gw_nr
|
||||
{
|
||||
public:
|
||||
virtual void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) = 0;
|
||||
};
|
||||
|
||||
class sdap_interface_rrc
|
||||
{
|
||||
public:
|
||||
struct bearer_cfg_t {
|
||||
bool is_data;
|
||||
bool add_downlink_header;
|
||||
bool add_uplink_header;
|
||||
uint32_t qfi;
|
||||
};
|
||||
virtual bool set_bearer_cfg(uint32_t lcid, const bearer_cfg_t& cfg) = 0;
|
||||
};
|
||||
|
||||
#endif // SRSRAN_UE_SDAP_INTERFACES_H
|
|
@ -29,12 +29,14 @@
|
|||
#define CFR_EMA_INIT_AVG_PWR 0.1
|
||||
|
||||
/**
|
||||
* @brief CFR manual threshold or PAPR limiting with Moving Average or EMA power averaging
|
||||
* @brief CFR manual threshold or PAPR limiting with CMA or EMA power averaging
|
||||
*/
|
||||
typedef enum SRSRAN_API {
|
||||
SRSRAN_CFR_THR_MANUAL = 1,
|
||||
SRSRAN_CFR_THR_AUTO_CMA = 2,
|
||||
SRSRAN_CFR_THR_AUTO_EMA = 3
|
||||
SRSRAN_CFR_THR_INVALID,
|
||||
SRSRAN_CFR_THR_MANUAL,
|
||||
SRSRAN_CFR_THR_AUTO_CMA,
|
||||
SRSRAN_CFR_THR_AUTO_EMA,
|
||||
SRSRAN_CFR_NOF_MODES
|
||||
} srsran_cfr_mode_t;
|
||||
|
||||
/**
|
||||
|
@ -124,4 +126,14 @@ SRSRAN_API int srsran_cfr_set_threshold(srsran_cfr_t* q, float thres);
|
|||
*/
|
||||
SRSRAN_API int srsran_cfr_set_papr(srsran_cfr_t* q, float papr);
|
||||
|
||||
/**
|
||||
* @brief Converts a string representing a CFR mode from the config files into srsran_cfr_mode_t type
|
||||
*
|
||||
* @param[in] mode_str the cfr.mode string coming from the config file
|
||||
* @return SRSRAN_CFR_THR_INVALID if mode_str is empty,
|
||||
* SRSRAN_CFR_THR_INVALID if mode_str is not recognised,
|
||||
* otherwise it returns the corresponding srsran_cfr_mode_t value.
|
||||
*/
|
||||
SRSRAN_API srsran_cfr_mode_t srsran_cfr_str2mode(const char* mode_str);
|
||||
|
||||
#endif // SRSRAN_CFR_H
|
||||
|
|
|
@ -49,7 +49,7 @@ typedef struct SRSRAN_API {
|
|||
cf_t* ce;
|
||||
uint32_t nof_re;
|
||||
float noise_estimate;
|
||||
float noise_estimate_dbm;
|
||||
float noise_estimate_dbFs;
|
||||
float rsrp;
|
||||
float rsrp_dBfs;
|
||||
float epre;
|
||||
|
|
|
@ -42,6 +42,7 @@ typedef struct {
|
|||
uint32_t pid; ///< HARQ process identifier
|
||||
uint16_t rnti;
|
||||
uint32_t pucch_resource_id;
|
||||
uint32_t n_cce;
|
||||
} srsran_harq_ack_resource_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -84,6 +84,8 @@ typedef struct SRSRAN_API {
|
|||
srsran_uci_value_t uci_data;
|
||||
float dmrs_correlation;
|
||||
float snr_db;
|
||||
float rssi_dbFs;
|
||||
float ni_dbFs;
|
||||
float correlation;
|
||||
bool detected;
|
||||
|
||||
|
|
|
@ -128,11 +128,13 @@ SRSRAN_API int srsran_ra_ul_nr_freq(const srsran_carrier_nr_t* carrier,
|
|||
* @brief Selects a valid PUCCH resource for transmission
|
||||
* @param pucch_cfg PUCCH configuration from upper layers
|
||||
* @param uci_cfg Uplink Control information configuration (and PDCCH context)
|
||||
* @param N_bwp_sz Uplink BWP size in nof_prb
|
||||
* @param[out] resource Selected resource for transmitting PUCCH
|
||||
* @return SRSRAN_SUCCESS if provided configuration is valid, SRSRAN_ERROR code otherwise
|
||||
*/
|
||||
SRSRAN_API int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
||||
const srsran_uci_cfg_nr_t* uci_cfg,
|
||||
uint32_t N_bwp_sz,
|
||||
srsran_pucch_nr_resource_t* resource);
|
||||
|
||||
/**
|
||||
|
|
|
@ -72,6 +72,73 @@ typedef struct {
|
|||
|
||||
typedef void (*srsran_rf_error_handler_t)(void* arg, srsran_rf_error_t error);
|
||||
|
||||
/* RF frontend API */
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const char* (*srsran_rf_devname)(void* h);
|
||||
int (*srsran_rf_start_rx_stream)(void* h, bool now);
|
||||
int (*srsran_rf_stop_rx_stream)(void* h);
|
||||
void (*srsran_rf_flush_buffer)(void* h);
|
||||
bool (*srsran_rf_has_rssi)(void* h);
|
||||
float (*srsran_rf_get_rssi)(void* h);
|
||||
void (*srsran_rf_suppress_stdout)(void* h);
|
||||
void (*srsran_rf_register_error_handler)(void* h, srsran_rf_error_handler_t error_handler, void* arg);
|
||||
int (*srsran_rf_open)(char* args, void** h);
|
||||
int (*srsran_rf_open_multi)(char* args, void** h, uint32_t nof_channels);
|
||||
int (*srsran_rf_close)(void* h);
|
||||
double (*srsran_rf_set_rx_srate)(void* h, double freq);
|
||||
int (*srsran_rf_set_rx_gain)(void* h, double gain);
|
||||
int (*srsran_rf_set_rx_gain_ch)(void* h, uint32_t ch, double gain);
|
||||
int (*srsran_rf_set_tx_gain)(void* h, double gain);
|
||||
int (*srsran_rf_set_tx_gain_ch)(void* h, uint32_t ch, double gain);
|
||||
double (*srsran_rf_get_rx_gain)(void* h);
|
||||
double (*srsran_rf_get_tx_gain)(void* h);
|
||||
srsran_rf_info_t* (*srsran_rf_get_info)(void* h);
|
||||
double (*srsran_rf_set_rx_freq)(void* h, uint32_t ch, double freq);
|
||||
double (*srsran_rf_set_tx_srate)(void* h, double freq);
|
||||
double (*srsran_rf_set_tx_freq)(void* h, uint32_t ch, double freq);
|
||||
void (*srsran_rf_get_time)(void* h, time_t* secs, double* frac_secs);
|
||||
void (*srsran_rf_sync_pps)(void* h);
|
||||
int (*srsran_rf_recv_with_time)(void* h,
|
||||
void* data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t* secs,
|
||||
double* frac_secs);
|
||||
int (*srsran_rf_recv_with_time_multi)(void* h,
|
||||
void** data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t* secs,
|
||||
double* frac_secs);
|
||||
int (*srsran_rf_send_timed)(void* h,
|
||||
void* data,
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
int (*srsran_rf_send_timed_multi)(void* h,
|
||||
void** data,
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
} rf_dev_t;
|
||||
|
||||
typedef struct {
|
||||
const char* plugin_name;
|
||||
void* dl_handle;
|
||||
rf_dev_t* rf_api;
|
||||
} srsran_rf_plugin_t;
|
||||
|
||||
SRSRAN_API int srsran_rf_load_plugins();
|
||||
|
||||
SRSRAN_API int srsran_rf_open(srsran_rf_t* h, char* args);
|
||||
|
||||
SRSRAN_API int srsran_rf_open_multi(srsran_rf_t* h, char* args, uint32_t nof_channels);
|
||||
|
|
|
@ -108,6 +108,8 @@ typedef struct SRSRAN_API {
|
|||
|
||||
srsran_ra_ul_pusch_hopping_t hopping;
|
||||
|
||||
srsran_cfr_cfg_t cfr_config;
|
||||
|
||||
cf_t* out_buffer;
|
||||
cf_t* refsignal;
|
||||
cf_t* srs_signal;
|
||||
|
@ -121,6 +123,8 @@ SRSRAN_API void srsran_ue_ul_free(srsran_ue_ul_t* q);
|
|||
|
||||
SRSRAN_API int srsran_ue_ul_set_cell(srsran_ue_ul_t* q, srsran_cell_t cell);
|
||||
|
||||
SRSRAN_API int srsran_ue_ul_set_cfr(srsran_ue_ul_t* q, const srsran_cfr_cfg_t* cfr);
|
||||
|
||||
SRSRAN_API int srsran_ue_ul_pregen_signals(srsran_ue_ul_t* q, srsran_ue_ul_cfg_t* cfg);
|
||||
|
||||
SRSRAN_API int srsran_ue_ul_dci_to_pusch_grant(srsran_ue_ul_t* q,
|
||||
|
|
|
@ -70,6 +70,15 @@ extern "C" {
|
|||
// Proportional moving average
|
||||
#define SRSRAN_VEC_PMA(average1, n1, average2, n2) (((average1) * (n1) + (average2) * (n2)) / ((n1) + (n2)))
|
||||
|
||||
// Safe Proportional moving average
|
||||
#ifdef __cplusplus
|
||||
#define SRSRAN_VEC_SAFE_PMA(average1, n1, average2, n2) \
|
||||
(std::isnormal((n1) + (n2)) ? SRSRAN_VEC_PMA(average1, n1, average2, n2) : (0))
|
||||
#else
|
||||
#define SRSRAN_VEC_SAFE_PMA(average1, n1, average2, n2) \
|
||||
(isnormal((n1) + (n2)) ? SRSRAN_VEC_PMA(average1, n1, average2, n2) : (0))
|
||||
#endif
|
||||
|
||||
// Exponential moving average
|
||||
#define SRSRAN_VEC_EMA(data, average, alpha) ((alpha) * (data) + (1 - alpha) * (average))
|
||||
|
||||
|
|
|
@ -143,7 +143,6 @@ public:
|
|||
virtual void get_buffer_state(uint32_t& tx_queue, uint32_t& prio_tx_queue) = 0;
|
||||
virtual void reestablish() = 0;
|
||||
virtual void empty_queue() = 0;
|
||||
virtual void discard_sdu(uint32_t pdcp_sn) = 0;
|
||||
virtual bool sdu_queue_is_full() = 0;
|
||||
virtual bool has_data() = 0;
|
||||
virtual void stop() = 0;
|
||||
|
@ -151,6 +150,7 @@ public:
|
|||
void set_bsr_callback(bsr_callback_t callback);
|
||||
|
||||
int write_sdu(unique_byte_buffer_t sdu);
|
||||
virtual void discard_sdu(uint32_t pdcp_sn);
|
||||
virtual uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) = 0;
|
||||
|
||||
bool tx_enabled = false;
|
||||
|
|
|
@ -204,25 +204,41 @@ public:
|
|||
const_iterator end() const { return list.end(); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rlc_ringbuffer_base {
|
||||
virtual ~rlc_ringbuffer_base() = default;
|
||||
virtual T& add_pdu(size_t sn) = 0;
|
||||
virtual void remove_pdu(size_t sn) = 0;
|
||||
virtual T& operator[](size_t sn) = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual bool has_sn(uint32_t sn) const = 0;
|
||||
};
|
||||
|
||||
template <class T, std::size_t WINDOW_SIZE>
|
||||
struct rlc_ringbuffer_t {
|
||||
T& add_pdu(size_t sn)
|
||||
struct rlc_ringbuffer_t : public rlc_ringbuffer_base<T> {
|
||||
~rlc_ringbuffer_t() = default;
|
||||
|
||||
T& add_pdu(size_t sn) override
|
||||
{
|
||||
srsran_expect(not has_sn(sn), "The same SN=%zd should not be added twice", sn);
|
||||
window.overwrite(sn, T(sn));
|
||||
return window[sn];
|
||||
}
|
||||
void remove_pdu(size_t sn)
|
||||
void remove_pdu(size_t sn) override
|
||||
{
|
||||
srsran_expect(has_sn(sn), "The removed SN=%zd is not in the window", sn);
|
||||
window.erase(sn);
|
||||
}
|
||||
T& operator[](size_t sn) { return window[sn]; }
|
||||
size_t size() const { return window.size(); }
|
||||
bool empty() const { return window.empty(); }
|
||||
void clear() { window.clear(); }
|
||||
T& operator[](size_t sn) override { return window[sn]; }
|
||||
size_t size() const override { return window.size(); }
|
||||
bool full() const override { return window.full(); }
|
||||
bool empty() const override { return window.empty(); }
|
||||
void clear() override { window.clear(); }
|
||||
|
||||
bool has_sn(uint32_t sn) const { return window.contains(sn); }
|
||||
bool has_sn(uint32_t sn) const override { return window.contains(sn); }
|
||||
|
||||
// Return the sum data bytes of all active PDUs (check PDU is non-null)
|
||||
uint32_t get_buffered_bytes()
|
||||
|
@ -309,41 +325,108 @@ private:
|
|||
uint32_t count = 0;
|
||||
};
|
||||
|
||||
struct rlc_amd_retx_t {
|
||||
uint32_t sn;
|
||||
bool is_segment;
|
||||
uint32_t so_start;
|
||||
uint32_t so_end;
|
||||
uint32_t current_so;
|
||||
struct rlc_amd_retx_base_t {
|
||||
const static uint32_t invalid_rlc_sn = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
uint32_t sn; ///< sequence number
|
||||
bool is_segment; ///< flag whether this is a segment or not
|
||||
uint32_t so_start; ///< offset to first byte of this segment
|
||||
// so_end or segment_length are different for LTE and NR, hence are defined in subclasses
|
||||
uint32_t current_so; ///< stores progressing SO during segmentation of this object
|
||||
|
||||
rlc_amd_retx_base_t() : sn(invalid_rlc_sn), is_segment(false), so_start(0), current_so(0) {}
|
||||
virtual ~rlc_amd_retx_base_t() = default;
|
||||
|
||||
/**
|
||||
* @brief overlaps implements a check whether the range of this retransmission object includes
|
||||
* the given segment offset
|
||||
* @param so the segment offset to check
|
||||
* @return true if the segment offset is covered by the retransmission object. Otherwise false
|
||||
*/
|
||||
virtual bool overlaps(uint32_t so) const = 0;
|
||||
};
|
||||
|
||||
template <std::size_t WINDOW_SIZE>
|
||||
class pdu_retx_queue
|
||||
struct rlc_amd_retx_lte_t : public rlc_amd_retx_base_t {
|
||||
uint32_t so_end; ///< offset to first byte beyond the end of this segment
|
||||
|
||||
rlc_amd_retx_lte_t() : rlc_amd_retx_base_t(), so_end(0) {}
|
||||
bool overlaps(uint32_t segment_offset) const override
|
||||
{
|
||||
return (segment_offset >= so_start) && (segment_offset < so_end);
|
||||
}
|
||||
};
|
||||
|
||||
struct rlc_amd_retx_nr_t : public rlc_amd_retx_base_t {
|
||||
uint32_t segment_length; ///< number of bytes contained in this segment
|
||||
|
||||
rlc_amd_retx_nr_t() : rlc_amd_retx_base_t(), segment_length(0) {}
|
||||
bool overlaps(uint32_t segment_offset) const override
|
||||
{
|
||||
return (segment_offset >= so_start) && (segment_offset < current_so + segment_length);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class pdu_retx_queue_base
|
||||
{
|
||||
public:
|
||||
rlc_amd_retx_t& push()
|
||||
virtual ~pdu_retx_queue_base() = default;
|
||||
virtual T& push() = 0;
|
||||
virtual void pop() = 0;
|
||||
virtual T& front() = 0;
|
||||
virtual void clear() = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
|
||||
virtual T& operator[](size_t idx) = 0;
|
||||
virtual const T& operator[](size_t idx) const = 0;
|
||||
|
||||
virtual bool has_sn(uint32_t sn) const = 0;
|
||||
virtual bool has_sn(uint32_t sn, uint32_t so) const = 0;
|
||||
};
|
||||
|
||||
template <class T, std::size_t WINDOW_SIZE>
|
||||
class pdu_retx_queue : public pdu_retx_queue_base<T>
|
||||
{
|
||||
public:
|
||||
~pdu_retx_queue() = default;
|
||||
|
||||
T& push() override
|
||||
{
|
||||
assert(not full());
|
||||
rlc_amd_retx_t& p = buffer[wpos];
|
||||
wpos = (wpos + 1) % WINDOW_SIZE;
|
||||
T& p = buffer[wpos];
|
||||
wpos = (wpos + 1) % WINDOW_SIZE;
|
||||
return p;
|
||||
}
|
||||
|
||||
void pop() { rpos = (rpos + 1) % WINDOW_SIZE; }
|
||||
void pop() override { rpos = (rpos + 1) % WINDOW_SIZE; }
|
||||
|
||||
rlc_amd_retx_t& front()
|
||||
T& front() override
|
||||
{
|
||||
assert(not empty());
|
||||
return buffer[rpos];
|
||||
}
|
||||
|
||||
void clear()
|
||||
T& operator[](size_t idx) override
|
||||
{
|
||||
srsran_assert(idx < size(), "Out-of-bounds access to element idx=%zd", idx);
|
||||
return buffer[(rpos + idx) % WINDOW_SIZE];
|
||||
}
|
||||
|
||||
const T& operator[](size_t idx) const override
|
||||
{
|
||||
srsran_assert(idx < size(), "Out-of-bounds access to element idx=%zd", idx);
|
||||
return buffer[(rpos + idx) % WINDOW_SIZE];
|
||||
}
|
||||
|
||||
void clear() override
|
||||
{
|
||||
wpos = 0;
|
||||
rpos = 0;
|
||||
}
|
||||
|
||||
bool has_sn(uint32_t sn) const
|
||||
bool has_sn(uint32_t sn) const override
|
||||
{
|
||||
for (size_t i = rpos; i != wpos; i = (i + 1) % WINDOW_SIZE) {
|
||||
if (buffer[i].sn == sn) {
|
||||
|
@ -353,14 +436,26 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
size_t size() const { return (wpos >= rpos) ? wpos - rpos : WINDOW_SIZE + wpos - rpos; }
|
||||
bool empty() const { return wpos == rpos; }
|
||||
bool full() const { return size() == WINDOW_SIZE - 1; }
|
||||
bool has_sn(uint32_t sn, uint32_t so) const override
|
||||
{
|
||||
for (size_t i = rpos; i != wpos; i = (i + 1) % WINDOW_SIZE) {
|
||||
if (buffer[i].sn == sn) {
|
||||
if (buffer[i].overlaps(so)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t size() const override { return (wpos >= rpos) ? wpos - rpos : WINDOW_SIZE + wpos - rpos; }
|
||||
bool empty() const override { return wpos == rpos; }
|
||||
bool full() const override { return size() == WINDOW_SIZE - 1; }
|
||||
|
||||
private:
|
||||
std::array<rlc_amd_retx_t, WINDOW_SIZE> buffer;
|
||||
size_t wpos = 0;
|
||||
size_t rpos = 0;
|
||||
std::array<T, WINDOW_SIZE> buffer;
|
||||
size_t wpos = 0;
|
||||
size_t rpos = 0;
|
||||
};
|
||||
|
||||
} // namespace srsran
|
||||
|
|
|
@ -68,7 +68,6 @@ public:
|
|||
void stop();
|
||||
|
||||
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
void discard_sdu(uint32_t discard_sn);
|
||||
bool sdu_queue_is_full();
|
||||
|
||||
bool has_data();
|
||||
|
@ -89,11 +88,11 @@ private:
|
|||
|
||||
int build_status_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
int build_retx_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx);
|
||||
int build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx);
|
||||
int build_data_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
void update_notification_ack_info(uint32_t rlc_sn);
|
||||
|
||||
int required_buffer_size(const rlc_amd_retx_t& retx);
|
||||
int required_buffer_size(const rlc_amd_retx_lte_t& retx);
|
||||
void retransmit_pdu(uint32_t sn);
|
||||
|
||||
// Helpers
|
||||
|
@ -147,7 +146,7 @@ private:
|
|||
|
||||
// Tx windows
|
||||
rlc_ringbuffer_t<rlc_amd_tx_pdu<rlc_amd_pdu_header_t>, RLC_AM_WINDOW_SIZE> tx_window;
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
pdu_retx_queue<rlc_amd_retx_lte_t, RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
pdcp_sn_vector_t notify_info_vec;
|
||||
|
||||
// Mutexes
|
||||
|
|
|
@ -62,7 +62,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t* status, uint8_t* payload);
|
|||
|
||||
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t* header);
|
||||
uint32_t rlc_am_packed_length(rlc_status_pdu_t* status);
|
||||
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
|
||||
uint32_t rlc_am_packed_length(rlc_amd_retx_lte_t retx);
|
||||
bool rlc_am_is_pdu_segment(uint8_t* payload);
|
||||
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status, uint32_t rx_win_min = 0);
|
||||
bool rlc_am_start_aligned(const uint8_t fi);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "srsran/common/buffer_pool.h"
|
||||
#include "srsran/common/common.h"
|
||||
#include "srsran/common/timers.h"
|
||||
#include "srsran/interfaces/pdcp_interface_types.h"
|
||||
#include "srsran/rlc/rlc_am_base.h"
|
||||
#include "srsran/rlc/rlc_am_data_structs.h"
|
||||
#include "srsran/rlc/rlc_am_nr_packing.h"
|
||||
|
@ -81,13 +82,12 @@ struct rlc_am_nr_tx_state_t {
|
|||
|
||||
struct rlc_amd_tx_pdu_nr {
|
||||
const uint32_t rlc_sn = INVALID_RLC_SN;
|
||||
const uint32_t pdcp_sn = INVALID_RLC_SN;
|
||||
uint32_t pdcp_sn = INVALID_RLC_SN;
|
||||
rlc_am_nr_pdu_header_t header = {};
|
||||
unique_byte_buffer_t sdu_buf = nullptr;
|
||||
uint32_t retx_count = 0;
|
||||
uint32_t retx_count = RETX_COUNT_NOT_STARTED;
|
||||
struct pdu_segment {
|
||||
uint32_t so = 0;
|
||||
uint32_t retx_count = 0;
|
||||
uint32_t payload_len = 0;
|
||||
};
|
||||
std::list<pdu_segment> segment_list;
|
||||
|
@ -105,22 +105,23 @@ public:
|
|||
uint32_t read_pdu(uint8_t* payload, uint32_t nof_bytes) final;
|
||||
void handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) final;
|
||||
|
||||
void discard_sdu(uint32_t discard_sn) final;
|
||||
bool sdu_queue_is_full() final;
|
||||
void reestablish() final;
|
||||
void stop() final;
|
||||
|
||||
int write_sdu(unique_byte_buffer_t sdu);
|
||||
void empty_queue() final;
|
||||
void empty_queue_no_lock();
|
||||
|
||||
// Data PDU helpers
|
||||
uint32_t build_new_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_new_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_continuation_sdu_segment(rlc_amd_tx_pdu_nr& tx_pdu, uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_retx_pdu(uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_t& retx, uint8_t* payload, uint32_t nof_bytes);
|
||||
bool is_retx_segmentation_required(const rlc_amd_retx_t& retx, uint32_t nof_bytes);
|
||||
uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_t& retx);
|
||||
uint32_t build_retx_pdu_without_segmentation(rlc_amd_retx_nr_t retx, uint8_t* payload, uint32_t nof_bytes);
|
||||
uint32_t build_retx_pdu_with_segmentation(rlc_amd_retx_nr_t& retx, uint8_t* payload, uint32_t nof_bytes);
|
||||
bool is_retx_segmentation_required(const rlc_amd_retx_nr_t& retx, uint32_t nof_bytes);
|
||||
uint32_t get_retx_expected_hdr_len(const rlc_amd_retx_nr_t& retx);
|
||||
|
||||
// Buffer State
|
||||
bool has_data() final;
|
||||
|
@ -132,18 +133,21 @@ public:
|
|||
uint32_t build_status_pdu(byte_buffer_t* payload, uint32_t nof_bytes);
|
||||
|
||||
// Polling
|
||||
uint8_t get_pdu_poll();
|
||||
uint8_t get_pdu_poll(uint32_t sn, bool is_retx, uint32_t sdu_bytes);
|
||||
|
||||
void stop() final;
|
||||
// Timers
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
// Window helpers
|
||||
bool inside_tx_window(uint32_t sn) const;
|
||||
|
||||
private:
|
||||
rlc_am* parent = nullptr;
|
||||
rlc_am_nr_rx* rx = nullptr;
|
||||
|
||||
uint32_t mod_nr = 4096;
|
||||
uint32_t mod_nr = cardinality(rlc_am_nr_sn_size_t());
|
||||
inline uint32_t tx_mod_base_nr(uint32_t sn) const;
|
||||
void check_sn_reached_max_retx(uint32_t sn);
|
||||
|
||||
/****************************************************************************
|
||||
* Configurable parameters
|
||||
|
@ -155,26 +159,41 @@ private:
|
|||
* Tx state variables
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
|
||||
***************************************************************************/
|
||||
struct rlc_am_nr_tx_state_t st = {};
|
||||
rlc_ringbuffer_t<rlc_amd_tx_pdu_nr, RLC_AM_WINDOW_SIZE> tx_window;
|
||||
struct rlc_am_nr_tx_state_t st = {};
|
||||
std::unique_ptr<rlc_ringbuffer_base<rlc_amd_tx_pdu_nr> > tx_window;
|
||||
|
||||
// Queues and buffers
|
||||
pdu_retx_queue<RLC_AM_WINDOW_SIZE> retx_queue;
|
||||
uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented.
|
||||
// Queues, buffers and container
|
||||
std::unique_ptr<pdu_retx_queue_base<rlc_amd_retx_nr_t> > retx_queue;
|
||||
uint32_t sdu_under_segmentation_sn = INVALID_RLC_SN; // SN of the SDU currently being segmented.
|
||||
pdcp_sn_vector_t notify_info_vec;
|
||||
|
||||
// Helper constants
|
||||
uint32_t min_hdr_size = 2;
|
||||
uint32_t min_hdr_size = 2; // Pre-initialized for 12 bit SN, updated by configure()
|
||||
uint32_t so_size = 2;
|
||||
uint32_t max_hdr_size = 4;
|
||||
uint32_t max_hdr_size = 4; // Pre-initialized for 12 bit SN, updated by configure()
|
||||
|
||||
/****************************************************************************
|
||||
* Tx constants
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.2
|
||||
***************************************************************************/
|
||||
inline uint32_t tx_window_size() const;
|
||||
|
||||
/****************************************************************************
|
||||
* TX timers
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.3
|
||||
***************************************************************************/
|
||||
srsran::timer_handler::unique_timer poll_retransmit_timer;
|
||||
|
||||
public:
|
||||
// Getters/Setters
|
||||
void set_tx_state(const rlc_am_nr_tx_state_t& st_) { st = st_; } // This should only be used for testing.
|
||||
rlc_am_nr_tx_state_t get_tx_state() { return st; } // This should only be used for testing.
|
||||
uint32_t get_tx_window_size() { return tx_window.size(); } // This should only be used for testing.
|
||||
void set_tx_state(const rlc_am_nr_tx_state_t& st_) { st = st_; } // This should only be used for testing.
|
||||
rlc_am_nr_tx_state_t get_tx_state() { return st; } // This should only be used for testing.
|
||||
uint32_t get_tx_window_utilization() { return tx_window->size(); } // This should only be used for testing.
|
||||
|
||||
// Debug Helper
|
||||
// Debug Helpers
|
||||
void debug_state() const;
|
||||
void info_state() const;
|
||||
void debug_window() const;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -231,7 +250,12 @@ public:
|
|||
bool inside_rx_window(uint32_t sn);
|
||||
void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu);
|
||||
void insert_received_segment(rlc_amd_rx_pdu_nr segment, rlc_amd_rx_sdu_nr_t::segment_list_t& segment_list) const;
|
||||
bool have_all_segments_been_received(const rlc_amd_rx_sdu_nr_t::segment_list_t& segment_list) const;
|
||||
/**
|
||||
* @brief update_segment_inventory This function updates the flags has_gap and fully_received of an SDU
|
||||
* according to the current inventory of received SDU segments
|
||||
* @param rx_sdu The SDU to operate on
|
||||
*/
|
||||
void update_segment_inventory(rlc_amd_rx_sdu_nr_t& rx_sdu) const;
|
||||
|
||||
// Metrics
|
||||
uint32_t get_sdu_rx_latency_ms() final;
|
||||
|
@ -242,17 +266,18 @@ public:
|
|||
|
||||
// Helpers
|
||||
void debug_state() const;
|
||||
void debug_window() const;
|
||||
|
||||
private:
|
||||
rlc_am* parent = nullptr;
|
||||
rlc_am_nr_tx* tx = nullptr;
|
||||
byte_buffer_pool* pool = nullptr;
|
||||
|
||||
uint32_t mod_nr = 4096;
|
||||
uint32_t mod_nr = cardinality(rlc_am_nr_sn_size_t());
|
||||
uint32_t rx_mod_base_nr(uint32_t sn) const;
|
||||
|
||||
// RX Window
|
||||
rlc_ringbuffer_t<rlc_amd_rx_sdu_nr_t, RLC_AM_WINDOW_SIZE> rx_window;
|
||||
std::unique_ptr<rlc_ringbuffer_base<rlc_amd_rx_sdu_nr_t> > rx_window;
|
||||
|
||||
// Mutexes
|
||||
std::mutex mutex;
|
||||
|
@ -271,16 +296,22 @@ private:
|
|||
rlc_am_nr_config_t cfg = {};
|
||||
|
||||
/****************************************************************************
|
||||
* Tx state variables
|
||||
* Rx state variables
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.1
|
||||
***************************************************************************/
|
||||
struct rlc_am_nr_rx_state_t st = {};
|
||||
|
||||
/****************************************************************************
|
||||
* Rx constants
|
||||
* Ref: 3GPP TS 38.322 version 16.2.0 Section 7.2
|
||||
***************************************************************************/
|
||||
inline uint32_t rx_window_size() const;
|
||||
|
||||
public:
|
||||
// Getters/Setters
|
||||
void set_rx_state(const rlc_am_nr_rx_state_t& st_) { st = st_; } // This should only be used for testing.
|
||||
rlc_am_nr_rx_state_t get_rx_state() { return st; } // This should only be used for testing.
|
||||
uint32_t get_rx_window_size() { return rx_window.size(); } // This should only be used for testing.
|
||||
void set_rx_state(const rlc_am_nr_rx_state_t& st_) { st = st_; } // This should only be used for testing.
|
||||
rlc_am_nr_rx_state_t get_rx_state() { return st; } // This should only be used for testing.
|
||||
uint32_t get_rx_window_size() { return rx_window->size(); } // This should only be used for testing.
|
||||
};
|
||||
|
||||
} // namespace srsran
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
|
||||
namespace srsran {
|
||||
|
||||
const uint32_t INVALID_RLC_SN = 0xFFFFFFFF;
|
||||
const uint32_t INVALID_RLC_SN = 0xFFFFFFFF;
|
||||
const uint32_t RETX_COUNT_NOT_STARTED = 0xFFFFFFFF;
|
||||
|
||||
///< AM NR PDU header
|
||||
struct rlc_am_nr_pdu_header_t {
|
||||
|
@ -69,6 +70,7 @@ struct rlc_amd_rx_pdu_nr_cmp {
|
|||
struct rlc_amd_rx_sdu_nr_t {
|
||||
uint32_t rlc_sn = 0;
|
||||
bool fully_received = false;
|
||||
bool has_gap = false;
|
||||
unique_byte_buffer_t buf;
|
||||
using segment_list_t = std::set<rlc_amd_rx_pdu_nr, rlc_amd_rx_pdu_nr_cmp>;
|
||||
segment_list_t segments;
|
||||
|
@ -85,14 +87,43 @@ struct rlc_amd_tx_sdu_nr_t {
|
|||
explicit rlc_amd_tx_sdu_nr_t(uint32_t rlc_sn_) : rlc_sn(rlc_sn_) {}
|
||||
};
|
||||
|
||||
///< AM NR Status PDU header (perhaps merge with LTE version)
|
||||
typedef struct {
|
||||
rlc_am_nr_control_pdu_type_t cpt;
|
||||
uint32_t ack_sn; ///< SN of the next not received RLC Data PDU
|
||||
uint16_t N_nack; ///< number of NACKs
|
||||
uint8_t nack_range; ///< number of consecutively lost RLC SDUs starting from and including NACK_SN
|
||||
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];
|
||||
} rlc_am_nr_status_pdu_t;
|
||||
constexpr uint32_t rlc_am_nr_status_pdu_sizeof_header_ack_sn = 3; ///< header fixed part and ACK SN
|
||||
constexpr uint32_t rlc_am_nr_status_pdu_sizeof_nack_sn_ext_12bit_sn = 2; ///< NACK SN and extension fields (12 bit SN)
|
||||
constexpr uint32_t rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn = 3; ///< NACK SN and extension fields (18 bit SN)
|
||||
constexpr uint32_t rlc_am_nr_status_pdu_sizeof_nack_so = 4; ///< NACK segment offsets (start and end)
|
||||
constexpr uint32_t rlc_am_nr_status_pdu_sizeof_nack_range = 1; ///< NACK range (nof consecutively lost SDUs)
|
||||
|
||||
/// AM NR Status PDU header
|
||||
class rlc_am_nr_status_pdu_t
|
||||
{
|
||||
private:
|
||||
/// Stored SN size required to compute the packed size
|
||||
rlc_am_nr_sn_size_t sn_size = rlc_am_nr_sn_size_t::nulltype;
|
||||
/// Internal NACK container; keep in sync with packed_size_
|
||||
std::vector<rlc_status_nack_t> nacks_ = {};
|
||||
/// Stores the current packed size; sync on each change of nacks_
|
||||
uint32_t packed_size_ = rlc_am_nr_status_pdu_sizeof_header_ack_sn;
|
||||
|
||||
void refresh_packed_size();
|
||||
uint32_t nack_size(const rlc_status_nack_t& nack) const;
|
||||
|
||||
public:
|
||||
/// CPT header
|
||||
rlc_am_nr_control_pdu_type_t cpt = rlc_am_nr_control_pdu_type_t::status_pdu;
|
||||
/// SN of the next not received RLC Data PDU
|
||||
uint32_t ack_sn = INVALID_RLC_SN;
|
||||
/// Read-only reference to NACKs
|
||||
const std::vector<rlc_status_nack_t>& nacks = nacks_;
|
||||
/// Read-only reference to packed size
|
||||
const uint32_t& packed_size = packed_size_;
|
||||
|
||||
rlc_am_nr_status_pdu_t(rlc_am_nr_sn_size_t sn_size);
|
||||
void reset();
|
||||
void push_nack(const rlc_status_nack_t& nack);
|
||||
const std::vector<rlc_status_nack_t>& get_nacks() const { return nacks_; }
|
||||
uint32_t get_packed_size() const { return packed_size; }
|
||||
bool trim(uint32_t max_packed_size);
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Header pack/unpack helper functions for NR
|
||||
|
@ -112,6 +143,10 @@ uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, b
|
|||
|
||||
uint32_t rlc_am_nr_packed_length(const rlc_am_nr_pdu_header_t& header);
|
||||
|
||||
/****************************************************************************
|
||||
* Status PDU pack/unpack helper functions for NR
|
||||
* Ref: 3GPP TS 38.322 v16.2.0 Section 6.2.2.5
|
||||
***************************************************************************/
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status);
|
||||
|
||||
|
@ -119,10 +154,16 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
|
|||
const uint32_t nof_bytes,
|
||||
const rlc_am_nr_sn_size_t sn_size,
|
||||
rlc_am_nr_status_pdu_t* status);
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status);
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status);
|
||||
|
||||
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
|
||||
const rlc_am_nr_sn_size_t sn_size,
|
||||
byte_buffer_t* pdu);
|
||||
int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu);
|
||||
int32_t rlc_am_nr_write_status_pdu_18bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu);
|
||||
|
||||
/**
|
||||
* Logs Status PDU into provided log channel, using fmt_str as format string
|
||||
|
@ -131,21 +172,35 @@ template <typename... Args>
|
|||
void log_rlc_am_nr_status_pdu_to_string(srslog::log_channel& log_ch,
|
||||
const char* fmt_str,
|
||||
rlc_am_nr_status_pdu_t* status,
|
||||
const std::string& rb_name,
|
||||
Args&&... args)
|
||||
{
|
||||
if (not log_ch.enabled()) {
|
||||
return;
|
||||
}
|
||||
fmt::memory_buffer buffer;
|
||||
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->N_nack);
|
||||
if (status->N_nack > 0) {
|
||||
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->nacks.size());
|
||||
if (status->nacks.size() > 0) {
|
||||
fmt::format_to(buffer, ", NACK_SN = ");
|
||||
for (uint32_t i = 0; i < status->N_nack; ++i) {
|
||||
if (status->nacks[i].has_so) {
|
||||
fmt::format_to(
|
||||
buffer, "[{} {}:{}]", status->nacks[i].nack_sn, status->nacks[i].so_start, status->nacks[i].so_end);
|
||||
for (uint32_t i = 0; i < status->nacks.size(); ++i) {
|
||||
if (status->nacks[i].has_nack_range) {
|
||||
if (status->nacks[i].has_so) {
|
||||
fmt::format_to(buffer,
|
||||
"[{} {}:{} r{}]",
|
||||
status->nacks[i].nack_sn,
|
||||
status->nacks[i].so_start,
|
||||
status->nacks[i].so_end,
|
||||
status->nacks[i].nack_range);
|
||||
} else {
|
||||
fmt::format_to(buffer, "[{} r{}]", status->nacks[i].nack_sn, status->nacks[i].nack_range);
|
||||
}
|
||||
} else {
|
||||
fmt::format_to(buffer, "[{}]", status->nacks[i].nack_sn);
|
||||
if (status->nacks[i].has_so) {
|
||||
fmt::format_to(
|
||||
buffer, "[{} {}:{}]", status->nacks[i].nack_sn, status->nacks[i].so_start, status->nacks[i].so_end);
|
||||
} else {
|
||||
fmt::format_to(buffer, "[{}]", status->nacks[i].nack_sn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,18 +210,21 @@ void log_rlc_am_nr_status_pdu_to_string(srslog::log_channel& log_ch,
|
|||
/*
|
||||
* Log NR AMD PDUs
|
||||
*/
|
||||
inline void log_rlc_am_nr_pdu_header_to_string(srslog::log_channel& log_ch, const rlc_am_nr_pdu_header_t& header)
|
||||
inline void log_rlc_am_nr_pdu_header_to_string(srslog::log_channel& log_ch,
|
||||
const rlc_am_nr_pdu_header_t& header,
|
||||
const std::string& rb_name)
|
||||
{
|
||||
if (not log_ch.enabled()) {
|
||||
return;
|
||||
}
|
||||
fmt::memory_buffer buffer;
|
||||
fmt::format_to(buffer,
|
||||
"[{}, P={}, SI={}, SN_SIZE={}, SN={}, SO={}",
|
||||
"{}: [{}, P={}, SI={}, SN_SIZE={}, SN={}, SO={}",
|
||||
rb_name,
|
||||
rlc_dc_field_text[header.dc],
|
||||
(header.p ? "1" : "0"),
|
||||
to_string_short(header.si),
|
||||
header.sn,
|
||||
to_string(header.sn_size),
|
||||
header.sn,
|
||||
header.so);
|
||||
fmt::format_to(buffer, "]");
|
||||
|
|
|
@ -43,6 +43,9 @@ namespace srsran {
|
|||
#define RLC_MAX_SDU_SIZE ((1 << 11) - 1) // Length of LI field is 11bits
|
||||
#define RLC_AM_MIN_DATA_PDU_SIZE (3) // AMD PDU with 10 bit SN (length of LI field is 11 bits) (No LI)
|
||||
|
||||
#define RLC_AM_NR_TYP_NACKS 512 // Expected number of NACKs in status PDU before expanding space by alloc
|
||||
#define RLC_AM_NR_MAX_NACKS 2048 // Maximum number of NACKs in status PDU
|
||||
|
||||
#define RlcDebug(fmt, ...) logger.debug("%s: " fmt, rb_name, ##__VA_ARGS__)
|
||||
#define RlcInfo(fmt, ...) logger.info("%s: " fmt, rb_name, ##__VA_ARGS__)
|
||||
#define RlcWarning(fmt, ...) logger.warning("%s: " fmt, rb_name, ##__VA_ARGS__)
|
||||
|
@ -171,17 +174,21 @@ public:
|
|||
|
||||
// NACK helper (for LTE and NR)
|
||||
struct rlc_status_nack_t {
|
||||
uint32_t nack_sn;
|
||||
bool has_so;
|
||||
uint16_t so_start;
|
||||
uint16_t so_end;
|
||||
uint32_t nack_sn; // Sequence Number (SN) of first missing SDU
|
||||
bool has_so; // NACKs continuous sequence of bytes [so_start..so_end]
|
||||
uint16_t so_start; // First missing byte in SDU with SN=nack_sn
|
||||
uint16_t so_end; // Last missing byte in SDU with SN=nack_sn or SN=nack_sn+nack_range-1 if has_nack_range.
|
||||
bool has_nack_range; // NACKs continuous sequence of SDUs
|
||||
uint8_t nack_range; // Number of SDUs being NACKed (including SN=nack_sn)
|
||||
|
||||
rlc_status_nack_t()
|
||||
{
|
||||
has_so = false;
|
||||
nack_sn = 0;
|
||||
so_start = 0;
|
||||
so_end = 0;
|
||||
has_so = false;
|
||||
nack_sn = 0;
|
||||
so_start = 0;
|
||||
so_end = 0;
|
||||
has_nack_range = false;
|
||||
nack_range = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ private:
|
|||
|
||||
bool configure(const rlc_config_t& cfg, std::string rb_name);
|
||||
uint32_t build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
|
||||
void discard_sdu(uint32_t discard_sn);
|
||||
uint32_t get_buffer_state();
|
||||
bool sdu_queue_is_full();
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ private:
|
|||
|
||||
bool configure(const rlc_config_t& cfg, std::string rb_name);
|
||||
uint32_t build_data_pdu(unique_byte_buffer_t pdu, uint8_t* payload, uint32_t nof_bytes);
|
||||
void discard_sdu(uint32_t discard_sn);
|
||||
uint32_t get_buffer_state();
|
||||
|
||||
private:
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace srsran {
|
|||
class undelivered_sdus_queue
|
||||
{
|
||||
public:
|
||||
explicit undelivered_sdus_queue(srsran::task_sched_handle task_sched);
|
||||
explicit undelivered_sdus_queue(srsran::task_sched_handle task_sched, uint32_t sn_mod);
|
||||
|
||||
bool empty() const { return count == 0; }
|
||||
bool is_full() const { return count >= capacity; }
|
||||
|
@ -82,8 +82,9 @@ public:
|
|||
private:
|
||||
const static uint32_t capacity = 4096;
|
||||
const static uint32_t invalid_sn = -1;
|
||||
uint32_t sn_mod = 0;
|
||||
|
||||
static uint32_t increment_sn(uint32_t sn) { return (sn + 1) % capacity; }
|
||||
uint32_t increment_sn(uint32_t sn) { return (sn + 1) % sn_mod; }
|
||||
|
||||
struct sdu_data {
|
||||
srsran::unique_byte_buffer_t sdu;
|
||||
|
|
|
@ -28,7 +28,7 @@ add_library(srsran_asn1 STATIC
|
|||
# ASN1 utils
|
||||
add_library(asn1_utils STATIC asn1_utils.cc)
|
||||
target_link_libraries(asn1_utils srsran_common)
|
||||
INSTALL(TARGETS asn1_utils DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS asn1_utils DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
# RRC ASN1 lib
|
||||
add_library(rrc_asn1 STATIC
|
||||
|
@ -54,29 +54,29 @@ add_library(rrc_asn1 STATIC
|
|||
# Compile RRC ASN1 optimized for size
|
||||
target_compile_options(rrc_asn1 PRIVATE "-Os")
|
||||
target_link_libraries(rrc_asn1 asn1_utils srsran_common)
|
||||
INSTALL(TARGETS rrc_asn1 DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS rrc_asn1 DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
# S1AP ASN1 lib
|
||||
add_library(s1ap_asn1 STATIC
|
||||
s1ap.cc s1ap_utils.cc)
|
||||
target_compile_options(s1ap_asn1 PRIVATE "-Os")
|
||||
target_link_libraries(s1ap_asn1 asn1_utils srsran_common)
|
||||
INSTALL(TARGETS s1ap_asn1 DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS s1ap_asn1 DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
# RRC NR ASN1
|
||||
add_library(rrc_nr_asn1 STATIC rrc_nr.cc rrc_nr_utils.cc)
|
||||
target_compile_options(rrc_nr_asn1 PRIVATE "-Os")
|
||||
target_link_libraries(rrc_nr_asn1 asn1_utils srsran_common)
|
||||
INSTALL(TARGETS rrc_nr_asn1 DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS rrc_nr_asn1 DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
# NGAP ASN1
|
||||
add_library(ngap_nr_asn1 STATIC ngap.cc)
|
||||
target_compile_options(ngap_nr_asn1 PRIVATE "-Os")
|
||||
target_link_libraries(ngap_nr_asn1 asn1_utils srsran_common)
|
||||
INSTALL(TARGETS ngap_nr_asn1 DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS ngap_nr_asn1 DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
# NAS 5G
|
||||
add_library(nas_5g_msg STATIC nas_5g_msg.cc nas_5g_ies.cc nas_5g_utils.cc)
|
||||
target_compile_options(nas_5g_msg PRIVATE "-Os")
|
||||
target_link_libraries(nas_5g_msg asn1_utils srsran_common)
|
||||
INSTALL(TARGETS nas_5g_msg DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS nas_5g_msg DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ SRSASN_CODE unpack_bits(T& val, Ptr& ptr, uint8_t& offset, const uint8_t* max_pt
|
|||
n_bits = 0;
|
||||
} else {
|
||||
auto mask = static_cast<uint8_t>((1u << (8u - offset)) - 1u);
|
||||
val += ((uint32_t)((*ptr) & mask)) << (n_bits - 8 + offset);
|
||||
val += static_cast<T>((*ptr) & mask) << (n_bits - 8 + offset);
|
||||
n_bits -= 8 - offset;
|
||||
offset = 0;
|
||||
ptr++;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -512,6 +512,21 @@ bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg,
|
|||
return true;
|
||||
}
|
||||
|
||||
void make_phy_search_space0_cfg(srsran_search_space_t* in_srsran_search_space)
|
||||
{
|
||||
in_srsran_search_space->id = 0;
|
||||
in_srsran_search_space->coreset_id = 0;
|
||||
in_srsran_search_space->type = srsran_search_space_type_common_0;
|
||||
in_srsran_search_space->nof_candidates[0] = 0;
|
||||
in_srsran_search_space->nof_candidates[1] = 0;
|
||||
in_srsran_search_space->nof_candidates[2] = 4;
|
||||
in_srsran_search_space->nof_candidates[3] = 2;
|
||||
in_srsran_search_space->nof_candidates[4] = 0;
|
||||
in_srsran_search_space->nof_formats = 1;
|
||||
in_srsran_search_space->formats[0] = srsran_dci_format_nr_1_0;
|
||||
in_srsran_search_space->duration = 1;
|
||||
}
|
||||
|
||||
bool make_phy_search_space_cfg(const search_space_s& search_space, srsran_search_space_t* in_srsran_search_space)
|
||||
{
|
||||
srsran_search_space_t srsran_search_space = {};
|
||||
|
|
|
@ -63,6 +63,6 @@ target_include_directories(srsran_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOUR
|
|||
target_link_libraries(srsran_common srsran_phy support srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES})
|
||||
target_compile_definitions(srsran_common PRIVATE ${BACKWARD_DEFINITIONS})
|
||||
|
||||
INSTALL(TARGETS srsran_common DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_common DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
|
|
@ -61,18 +61,28 @@ bool ue_bearer_manager_impl::has_active_radio_bearer(uint32_t eps_bearer_id)
|
|||
return bearers.count(eps_bearer_id) > 0;
|
||||
}
|
||||
|
||||
ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_radio_bearer(uint32_t eps_bearer_id)
|
||||
ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_radio_bearer(uint32_t eps_bearer_id) const
|
||||
{
|
||||
auto it = bearers.find(eps_bearer_id);
|
||||
return it != bearers.end() ? it->second : invalid_rb;
|
||||
}
|
||||
|
||||
ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_eps_bearer_id_for_lcid(uint32_t lcid)
|
||||
ue_bearer_manager_impl::radio_bearer_t ue_bearer_manager_impl::get_eps_bearer_id_for_lcid(uint32_t lcid) const
|
||||
{
|
||||
auto lcid_it = lcid_to_eps_bearer_id.find(lcid);
|
||||
return lcid_it != lcid_to_eps_bearer_id.end() ? bearers.at(lcid_it->second) : invalid_rb;
|
||||
}
|
||||
|
||||
bool ue_bearer_manager_impl::set_five_qi(uint32_t eps_bearer_id, uint16_t five_qi)
|
||||
{
|
||||
auto it = bearers.find(eps_bearer_id);
|
||||
if (it == bearers.end()) {
|
||||
return false;
|
||||
}
|
||||
it->second.five_qi = five_qi;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace srsran
|
||||
|
||||
|
@ -185,7 +195,7 @@ bool enb_bearer_manager::has_active_radio_bearer(uint16_t rnti, uint32_t eps_bea
|
|||
return user_it->second.has_active_radio_bearer(eps_bearer_id);
|
||||
}
|
||||
|
||||
enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_lcid_bearer(uint16_t rnti, uint32_t lcid)
|
||||
enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_lcid_bearer(uint16_t rnti, uint32_t lcid) const
|
||||
{
|
||||
auto user_it = users_map.find(rnti);
|
||||
if (user_it == users_map.end()) {
|
||||
|
@ -203,4 +213,13 @@ enb_bearer_manager::radio_bearer_t enb_bearer_manager::get_radio_bearer(uint16_t
|
|||
return user_it->second.get_radio_bearer(eps_bearer_id);
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
||||
bool enb_bearer_manager::set_five_qi(uint16_t rnti, uint32_t eps_bearer_id, uint16_t five_qi)
|
||||
{
|
||||
auto user_it = users_map.find(rnti);
|
||||
if (user_it == users_map.end()) {
|
||||
return false;
|
||||
}
|
||||
return user_it->second.set_five_qi(eps_bearer_id, five_qi);
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
||||
|
|
|
@ -330,7 +330,7 @@ bool phy_cfg_nr_t::get_pucch_uci_cfg(const srsran_slot_cfg_t& slot_cfg,
|
|||
srsran_pucch_nr_resource_t& resource) const
|
||||
{
|
||||
// Select PUCCH resource
|
||||
if (srsran_ra_ul_nr_pucch_resource(&pucch, &uci_cfg, &resource) < SRSRAN_SUCCESS) {
|
||||
if (srsran_ra_ul_nr_pucch_resource(&pucch, &uci_cfg, carrier.nof_prb, &resource) < SRSRAN_SUCCESS) {
|
||||
ERROR("Selecting PUCCH resource");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -22,4 +22,4 @@ set(SOURCES gtpu.cc)
|
|||
|
||||
add_library(srsran_gtpu STATIC ${SOURCES})
|
||||
target_link_libraries(srsran_gtpu srsran_common srsran_asn1 ${ATOMIC_LIBS})
|
||||
INSTALL(TARGETS srsran_gtpu DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_gtpu DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
|
|
@ -22,6 +22,6 @@ SET(SOURCES pdu.cc pdu_queue.cc mac_sch_pdu_nr.cc mac_rar_pdu_nr.cc)
|
|||
|
||||
add_library(srsran_mac STATIC ${SOURCES})
|
||||
target_link_libraries(srsran_mac srsran_common)
|
||||
INSTALL(TARGETS srsran_mac DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_mac DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
add_subdirectory(test)
|
|
@ -25,4 +25,4 @@ set(SOURCES pdcp.cc
|
|||
|
||||
add_library(srsran_pdcp STATIC ${SOURCES})
|
||||
target_link_libraries(srsran_pdcp srsran_common srsran_asn1 ${ATOMIC_LIBS})
|
||||
INSTALL(TARGETS srsran_pdcp DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_pdcp DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
|
|
@ -100,7 +100,7 @@ bool pdcp_entity_lte::configure(const pdcp_config_t& cnfg_)
|
|||
logger.info("Status Report Required: %s", cfg.status_report_required ? "True" : "False");
|
||||
|
||||
if (is_drb() and not rlc->rb_is_um(lcid)) {
|
||||
undelivered_sdus = std::unique_ptr<undelivered_sdus_queue>(new undelivered_sdus_queue(task_sched));
|
||||
undelivered_sdus = std::unique_ptr<undelivered_sdus_queue>(new undelivered_sdus_queue(task_sched, maximum_pdcp_sn));
|
||||
rx_counts_info.reserve(reordering_window);
|
||||
}
|
||||
|
||||
|
@ -230,6 +230,10 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu, int upper_sn)
|
|||
// Pass PDU to lower layers
|
||||
metrics.num_tx_pdus++;
|
||||
metrics.num_tx_pdu_bytes += sdu->N_bytes;
|
||||
// Count TX'd bytes as if they were ACK'd if RLC is UM
|
||||
if (rlc->rb_is_um(lcid)) {
|
||||
metrics.num_tx_acked_bytes = metrics.num_tx_pdu_bytes;
|
||||
}
|
||||
rlc->write_sdu(lcid, std::move(sdu));
|
||||
}
|
||||
|
||||
|
@ -867,7 +871,7 @@ void pdcp_entity_lte::reset_metrics()
|
|||
/****************************************************************************
|
||||
* Undelivered SDUs queue helpers
|
||||
***************************************************************************/
|
||||
undelivered_sdus_queue::undelivered_sdus_queue(srsran::task_sched_handle task_sched)
|
||||
undelivered_sdus_queue::undelivered_sdus_queue(srsran::task_sched_handle task_sched, uint32_t sn_mod) : sn_mod(sn_mod)
|
||||
{
|
||||
for (auto& e : sdus) {
|
||||
e.discard_timer = task_sched.get_unique_timer();
|
||||
|
|
|
@ -59,4 +59,4 @@ set(srsran_srcs $<TARGET_OBJECTS:srsran_agc>
|
|||
|
||||
add_library(srsran_phy STATIC ${srsran_srcs} )
|
||||
target_link_libraries(srsran_phy pthread m ${FFT_LIBRARIES})
|
||||
INSTALL(TARGETS srsran_phy DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_phy DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
|
|
@ -162,6 +162,10 @@ int srsran_cfr_init(srsran_cfr_t* q, srsran_cfr_cfg_t* cfg)
|
|||
ERROR("Error, invalid configuration");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (cfg->cfr_mode == SRSRAN_CFR_THR_INVALID) {
|
||||
ERROR("Error, invalid CFR mode");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (cfg->cfr_mode == SRSRAN_CFR_THR_MANUAL && cfg->manual_thr <= 0) {
|
||||
ERROR("Error, invalid configuration for manual threshold");
|
||||
goto clean_exit;
|
||||
|
@ -330,6 +334,9 @@ bool srsran_cfr_params_valid(srsran_cfr_cfg_t* cfr_conf)
|
|||
if (cfr_conf == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (cfr_conf->cfr_mode == SRSRAN_CFR_THR_INVALID) {
|
||||
return false;
|
||||
}
|
||||
if (cfr_conf->alpha < 0 || cfr_conf->alpha > 1) {
|
||||
return false;
|
||||
}
|
||||
|
@ -374,3 +381,22 @@ int srsran_cfr_set_papr(srsran_cfr_t* q, float papr)
|
|||
q->max_papr_lin = srsran_convert_dB_to_power(q->cfg.max_papr_db);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
srsran_cfr_mode_t srsran_cfr_str2mode(const char* mode_str)
|
||||
{
|
||||
srsran_cfr_mode_t ret;
|
||||
if (strcmp(mode_str, "")) {
|
||||
if (!strcmp(mode_str, "manual")) {
|
||||
ret = SRSRAN_CFR_THR_MANUAL;
|
||||
} else if (!strcmp(mode_str, "auto_cma")) {
|
||||
ret = SRSRAN_CFR_THR_AUTO_CMA;
|
||||
} else if (!strcmp(mode_str, "auto_ema")) {
|
||||
ret = SRSRAN_CFR_THR_AUTO_EMA;
|
||||
} else {
|
||||
ret = SRSRAN_CFR_THR_INVALID; // mode_str is not recognised
|
||||
}
|
||||
} else {
|
||||
ret = SRSRAN_CFR_THR_INVALID; // mode_str is empty
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -30,13 +30,9 @@
|
|||
|
||||
#define MAX_ACPR_DB -100
|
||||
|
||||
// CFR type test args
|
||||
static char cfr_manual_str[] = "manual";
|
||||
static char cfr_auto_cma_str[] = "auto_cma";
|
||||
static char cfr_auto_ema_str[] = "auto_ema";
|
||||
|
||||
// Default CFR type
|
||||
static char* cfr_type_arg = cfr_manual_str;
|
||||
static char* cfr_mode_str = "manual";
|
||||
|
||||
static int nof_prb = -1;
|
||||
static srsran_cp_t cp = SRSRAN_CP_NORM;
|
||||
|
@ -69,7 +65,7 @@ static void usage(char* prog)
|
|||
printf("\t-e extended cyclic prefix [Default Normal]\n");
|
||||
printf("\t-f Number of frames [Default %d]\n", nof_frames);
|
||||
printf("\t-r Number of repetitions [Default %d]\n", nof_repetitions);
|
||||
printf("\t-m CFR mode: %s, %s, %s [Default %s]\n", cfr_manual_str, cfr_auto_cma_str, cfr_auto_ema_str, cfr_type_arg);
|
||||
printf("\t-m CFR mode: manual, auto_cma, auto_ema [Default %s]\n", cfr_mode_str);
|
||||
printf("\t-d Use DC subcarrier: [Default DC empty]\n");
|
||||
printf("\t-a CFR alpha: [Default %.2f]\n", alpha);
|
||||
printf("\t-t CFR manual threshold: [Default %.2f]\n", thr_manual);
|
||||
|
@ -98,7 +94,7 @@ static int parse_args(int argc, char** argv)
|
|||
nof_frames = (int)strtol(argv[optind], NULL, 10);
|
||||
break;
|
||||
case 'm':
|
||||
cfr_type_arg = argv[optind];
|
||||
cfr_mode_str = argv[optind];
|
||||
break;
|
||||
case 'a':
|
||||
alpha = strtof(argv[optind], NULL);
|
||||
|
@ -149,13 +145,8 @@ int main(int argc, char** argv)
|
|||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!strcmp(cfr_type_arg, cfr_manual_str)) {
|
||||
cfr_mode = SRSRAN_CFR_THR_MANUAL;
|
||||
} else if (!strcmp(cfr_type_arg, cfr_auto_cma_str)) {
|
||||
cfr_mode = SRSRAN_CFR_THR_AUTO_CMA;
|
||||
} else if (!strcmp(cfr_type_arg, cfr_auto_ema_str)) {
|
||||
cfr_mode = SRSRAN_CFR_THR_AUTO_EMA;
|
||||
} else {
|
||||
cfr_mode = srsran_cfr_str2mode(cfr_mode_str);
|
||||
if (cfr_mode == SRSRAN_CFR_THR_INVALID) {
|
||||
ERROR("CFR mode is not recognised");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
@ -202,6 +193,11 @@ int main(int argc, char** argv)
|
|||
cfr_tx_cfg.ema_alpha = ema_alpha;
|
||||
cfr_tx_cfg.dc_sc = dc_empty;
|
||||
|
||||
if (!srsran_cfr_params_valid(&cfr_tx_cfg)) {
|
||||
ERROR("Invalid CFR configuration");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (srsran_cfr_init(&cfr, &cfr_tx_cfg)) {
|
||||
ERROR("Error initializing CFR");
|
||||
goto clean_exit;
|
||||
|
|
|
@ -355,16 +355,30 @@ static void chest_ul_estimate(srsran_chest_ul_t* q,
|
|||
}
|
||||
}
|
||||
|
||||
// Estimate received pilot power
|
||||
// Measure reference signal RE average power
|
||||
cf_t corr = srsran_vec_acc_cc(q->pilot_recv_signal, nslots * nrefs_sym) / (nslots * nrefs_sym);
|
||||
float rsrp_avg = __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
||||
|
||||
// Measure EPRE
|
||||
float epre = srsran_vec_avg_power_cf(q->pilot_recv_signal, nslots * nrefs_sym);
|
||||
|
||||
// RSRP shall not be greater than EPRE
|
||||
rsrp_avg = SRSRAN_MIN(rsrp_avg, epre);
|
||||
|
||||
// Calculate SNR
|
||||
if (isnormal(res->noise_estimate)) {
|
||||
res->snr = srsran_vec_avg_power_cf(q->pilot_recv_signal, nslots * nrefs_sym) / res->noise_estimate;
|
||||
res->snr = epre / res->noise_estimate;
|
||||
} else {
|
||||
res->snr = NAN;
|
||||
}
|
||||
|
||||
// Convert measurements in logarithm scale
|
||||
res->snr_db = srsran_convert_power_to_dB(res->snr);
|
||||
res->noise_estimate_dbm = srsran_convert_power_to_dBm(res->noise_estimate);
|
||||
// Set EPRE and RSRP
|
||||
res->epre = epre;
|
||||
res->epre_dBfs = srsran_convert_power_to_dB(res->epre);
|
||||
res->rsrp = rsrp_avg;
|
||||
res->rsrp_dBfs = srsran_convert_power_to_dB(res->rsrp);
|
||||
res->snr_db = srsran_convert_power_to_dB(res->snr);
|
||||
res->noise_estimate_dbFs = srsran_convert_power_to_dBm(res->noise_estimate);
|
||||
}
|
||||
|
||||
int srsran_chest_ul_estimate_pusch(srsran_chest_ul_t* q,
|
||||
|
@ -479,15 +493,12 @@ int srsran_chest_ul_estimate_pucch(srsran_chest_ul_t* q,
|
|||
srsran_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf);
|
||||
}
|
||||
|
||||
// Measure power
|
||||
float rsrp_avg = 0.0f;
|
||||
for (int ns = 0; ns < SRSRAN_NOF_SLOTS_PER_SF; ns++) {
|
||||
for (int i = 0; i < n_rs; i++) {
|
||||
cf_t corr = srsran_vec_acc_cc(q->pilot_estimates, SRSRAN_NOF_SLOTS_PER_SF * SRSRAN_NRE * n_rs) / (SRSRAN_NRE);
|
||||
rsrp_avg += __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
||||
}
|
||||
}
|
||||
rsrp_avg /= SRSRAN_NOF_SLOTS_PER_SF * n_rs;
|
||||
// Measure reference signal RE average power
|
||||
cf_t corr = srsran_vec_acc_cc(q->pilot_estimates, SRSRAN_NOF_SLOTS_PER_SF * SRSRAN_NRE * n_rs) /
|
||||
(SRSRAN_NOF_SLOTS_PER_SF * SRSRAN_NRE * n_rs);
|
||||
float rsrp_avg = __real__ corr * __real__ corr + __imag__ corr * __imag__ corr;
|
||||
|
||||
// Measure EPRE
|
||||
float epre = srsran_vec_avg_power_cf(q->pilot_estimates, SRSRAN_NOF_SLOTS_PER_SF * SRSRAN_NRE * n_rs);
|
||||
|
||||
// RSRP shall not be greater than EPRE
|
||||
|
@ -562,11 +573,11 @@ int srsran_chest_ul_estimate_pucch(srsran_chest_ul_t* q,
|
|||
if (fpclassify(res->noise_estimate) == FP_ZERO) {
|
||||
res->noise_estimate = FLT_MIN;
|
||||
}
|
||||
res->noise_estimate_dbm = srsran_convert_power_to_dBm(res->noise_estimate);
|
||||
res->noise_estimate_dbFs = srsran_convert_power_to_dBm(res->noise_estimate);
|
||||
|
||||
// Estimate SINR
|
||||
if (isnormal(res->noise_estimate)) {
|
||||
res->snr = res->rsrp / res->noise_estimate;
|
||||
res->snr = res->epre / res->noise_estimate;
|
||||
res->snr_db = srsran_convert_power_to_dB(res->snr);
|
||||
} else {
|
||||
res->snr = NAN;
|
||||
|
|
|
@ -120,43 +120,58 @@ int srsran_dmrs_pucch_format1_put(const srsran_pucch_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// First symbol index
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
uint32_t l = m * 2;
|
||||
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Calculating alpha");
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||
// Get number of symbols carrying DMRS
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
// Get the starting PRB
|
||||
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
for (uint32_t m = 0; m < n_pucch; m++, l += 2) {
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Put z in the grid
|
||||
srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE);
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Calculating alpha");
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 DMRS TX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f; z=",
|
||||
m_prime,
|
||||
m,
|
||||
__real__ w_i_m,
|
||||
__imag__ w_i_m);
|
||||
srsran_vec_fprint_c(stdout, z, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// Put z in the grid
|
||||
srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
@ -186,50 +201,71 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, 0);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
cf_t ce[SRSRAN_PUCCH_NR_FORMAT1_N_MAX][SRSRAN_NRE];
|
||||
|
||||
// Prevent ce[m] overflow
|
||||
assert(n_pucch <= SRSRAN_PUCCH_NR_FORMAT1_N_MAX);
|
||||
uint32_t start_rb_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX];
|
||||
uint32_t symbol_idx[SRSRAN_PUCCH_NR_FORMAT1_N_MAX];
|
||||
cf_t ce[SRSRAN_PUCCH_NR_FORMAT1_N_MAX][SRSRAN_NRE];
|
||||
|
||||
// First symbol index
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
// Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
uint32_t l = m * 2;
|
||||
|
||||
// Get start of the sequence in resource grid
|
||||
const cf_t* slot_symbols_ptr =
|
||||
&slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Calculating alpha");
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
uint32_t n_pucch_sum = 0;
|
||||
for (uint32_t m_prime = 0, l = 0; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||
// Get number of symbols carrying DMRS
|
||||
uint32_t n_pucch = dmrs_pucch_format1_n_pucch(resource, m_prime);
|
||||
if (n_pucch == 0) {
|
||||
ERROR("Error getting number of symbols");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
// Prevent ce[m] overflow
|
||||
assert(n_pucch <= SRSRAN_PUCCH_NR_FORMAT1_N_MAX);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
// Get the starting PRB
|
||||
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||
start_rb_idx[n_pucch_sum] = starting_prb;
|
||||
|
||||
// TODO: can ce[m] overflow?
|
||||
// Calculate least square estimates for this symbol
|
||||
srsran_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[m], SRSRAN_NRE);
|
||||
for (uint32_t m = 0; m < n_pucch; m++, l += 2) { // Clause 6.4.1.3.1.2 specifies l=0,2,4...
|
||||
symbol_idx[n_pucch_sum] = l + l_prime;
|
||||
|
||||
// Get start of the sequence in resource grid
|
||||
const cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
ERROR("Calculating alpha");
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
INFO("[PUCCH Format 1 DMRS RX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f", m_prime, m, __real__ w_i_m, __imag__ w_i_m);
|
||||
srsran_vec_fprint_c(stdout, z, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// TODO: can ce[m] overflow?
|
||||
// Calculate least square estimates for this symbol
|
||||
srsran_vec_prod_conj_ccc(slot_symbols_ptr, z, ce[n_pucch_sum], SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 DMRS RX] ce[%d]=", n_pucch_sum);
|
||||
srsran_vec_fprint_c(stdout, ce[n_pucch_sum], SRSRAN_NRE);
|
||||
}
|
||||
n_pucch_sum++;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform measurements
|
||||
|
@ -237,7 +273,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
float epre = 0.0f;
|
||||
float ta_err = 0.0f;
|
||||
cf_t corr[SRSRAN_PUCCH_NR_FORMAT1_N_MAX] = {};
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
for (uint32_t m = 0; m < n_pucch_sum; m++) {
|
||||
corr[m] = srsran_vec_acc_cc(ce[m], SRSRAN_NRE) / SRSRAN_NRE;
|
||||
rsrp += SRSRAN_CSQABS(corr[m]);
|
||||
epre += srsran_vec_avg_power_cf(ce[m], SRSRAN_NRE);
|
||||
|
@ -245,9 +281,9 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
}
|
||||
|
||||
// Average measurements
|
||||
rsrp /= n_pucch;
|
||||
epre /= n_pucch;
|
||||
ta_err /= n_pucch;
|
||||
rsrp /= n_pucch_sum;
|
||||
epre /= n_pucch_sum;
|
||||
ta_err /= n_pucch_sum;
|
||||
|
||||
// Set power measures
|
||||
rsrp = SRSRAN_MIN(rsrp, epre);
|
||||
|
@ -256,7 +292,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
res->epre = epre;
|
||||
res->epre_dBfs = srsran_convert_power_to_dB(epre);
|
||||
res->noise_estimate = SRSRAN_MAX(epre - rsrp, 1e-6f);
|
||||
res->noise_estimate_dbm = srsran_convert_power_to_dB(res->noise_estimate);
|
||||
res->noise_estimate_dbFs = srsran_convert_power_to_dB(res->noise_estimate);
|
||||
res->snr = rsrp / res->noise_estimate;
|
||||
res->snr_db = srsran_convert_power_to_dB(res->snr);
|
||||
|
||||
|
@ -271,16 +307,16 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
}
|
||||
|
||||
// Measure CFO
|
||||
if (n_pucch > 1) {
|
||||
if (n_pucch_sum > 1) {
|
||||
float cfo_avg_hz = 0.0f;
|
||||
for (uint32_t m = 0; m < n_pucch - 1; m++) {
|
||||
for (uint32_t m = 0; m < n_pucch_sum - 1; m++) {
|
||||
uint32_t l0 = resource->start_symbol_idx + m * 2;
|
||||
uint32_t l1 = resource->start_symbol_idx + (m + 1) * 2;
|
||||
float time_diff = srsran_symbol_distance_s(l0, l1, q->carrier.scs);
|
||||
float phase_diff = cargf(corr[m + 1] * conjf(corr[m]));
|
||||
|
||||
if (isnormal(time_diff)) {
|
||||
cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (n_pucch - 1));
|
||||
cfo_avg_hz += phase_diff / (2.0f * M_PI * time_diff * (n_pucch_sum - 1));
|
||||
}
|
||||
}
|
||||
res->cfo_hz = cfo_avg_hz;
|
||||
|
@ -292,11 +328,10 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
// ... Not implemented
|
||||
|
||||
// Interpolates between DMRS symbols
|
||||
for (uint32_t m = 0; m < n_pucch; m++) {
|
||||
uint32_t l = m * 2 + 1;
|
||||
cf_t* ce_ptr = &res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
for (uint32_t m = 0; m < n_pucch_sum; m++) {
|
||||
cf_t* ce_ptr = &res->ce[m * SRSRAN_NRE];
|
||||
|
||||
if (m != n_pucch - 1) {
|
||||
if (m != n_pucch_sum - 1) {
|
||||
// If it is not the last symbol with DMRS, average between
|
||||
srsran_vec_sum_ccc(ce[m], ce[m + 1], ce_ptr, SRSRAN_NRE);
|
||||
srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE);
|
||||
|
@ -306,7 +341,7 @@ int srsran_dmrs_pucch_format1_estimate(const srsran_pucch_nr_t* q,
|
|||
srsran_vec_sub_ccc(ce_ptr, ce[m - 1], ce_ptr, SRSRAN_NRE);
|
||||
srsran_vec_sc_prod_cfc(ce_ptr, 0.5f, ce_ptr, SRSRAN_NRE);
|
||||
} else {
|
||||
// Simply copy the
|
||||
// Simply copy the estimated channel
|
||||
srsran_vec_cf_copy(ce_ptr, ce[m], SRSRAN_NRE);
|
||||
}
|
||||
}
|
||||
|
@ -432,7 +467,7 @@ int srsran_dmrs_pucch_format2_estimate(const srsran_pucch_nr_t* q,
|
|||
res->epre = epre;
|
||||
res->epre_dBfs = srsran_convert_power_to_dB(epre);
|
||||
res->noise_estimate = SRSRAN_MAX(epre - rsrp, 1e-6f);
|
||||
res->noise_estimate_dbm = srsran_convert_power_to_dB(res->noise_estimate);
|
||||
res->noise_estimate_dbFs = srsran_convert_power_to_dB(res->noise_estimate);
|
||||
res->snr = rsrp / res->noise_estimate;
|
||||
res->snr_db = srsran_convert_power_to_dB(res->snr);
|
||||
|
||||
|
|
|
@ -159,12 +159,12 @@ int srs_test_context_run(srs_test_context_t* q)
|
|||
INFO("RESULTS: tti=%d; snr_db=%+.1f; noise_estimate_dbm=%+.1f; ta_us=%+.1f;",
|
||||
ul_sf_cfg.tti,
|
||||
q->chest_ul_res.snr_db,
|
||||
q->chest_ul_res.noise_estimate_dbm,
|
||||
q->chest_ul_res.noise_estimate_dbFs,
|
||||
q->chest_ul_res.ta_us);
|
||||
|
||||
// Assert SRS measurements
|
||||
TESTASSERT(fabsf(q->chest_ul_res.snr_db - snr_db) < CHEST_TEST_SRS_SNR_DB_TOLERANCE);
|
||||
TESTASSERT(fabsf(q->chest_ul_res.noise_estimate_dbm - n0_dbm) < CHEST_TEST_SRS_SNR_DB_TOLERANCE);
|
||||
TESTASSERT(fabsf(q->chest_ul_res.noise_estimate_dbFs - n0_dbm) < CHEST_TEST_SRS_SNR_DB_TOLERANCE);
|
||||
TESTASSERT(fabsf(q->chest_ul_res.ta_us) < CHEST_TEST_SRS_TA_US_TOLERANCE);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
|
|
@ -37,3 +37,12 @@ target_link_libraries(sliv_test srsran_phy)
|
|||
add_test(sliv_test_14 sliv_test 14)
|
||||
add_test(sliv_test_52 sliv_test 48)
|
||||
add_test(sliv_test_52 sliv_test 52)
|
||||
|
||||
########################################################################
|
||||
# PHY COMMON TEST
|
||||
########################################################################
|
||||
|
||||
add_executable(phy_common_test phy_common_test.c)
|
||||
target_link_libraries(phy_common_test srsran_phy)
|
||||
|
||||
add_test(phy_common_test phy_common_test)
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "srsran/phy/common/phy_common.h"
|
||||
|
||||
int srsran_default_rates_test()
|
||||
{
|
||||
// Verify calculated sample rates for all valid PRB sizes.
|
||||
// By default we use the reduced 3/4 sampling to save bandwidth on the fronthaul.
|
||||
#ifdef FORCE_STANDARD_RATE
|
||||
srsran_use_standard_symbol_size(false);
|
||||
#endif
|
||||
TESTASSERT(srsran_sampling_freq_hz(6) == 1920000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(15) == 3840000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(25) == 5760000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(50) == 11520000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(75) == 15360000); // need to use default rate for 15 MHz BW
|
||||
TESTASSERT(srsran_sampling_freq_hz(100) == 23040000);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int lte_standard_rates_test()
|
||||
{
|
||||
// Verify calculated sample rates for all valid PRB sizes.
|
||||
// Enable standard LTE rates (required by some RF HW).
|
||||
srsran_use_standard_symbol_size(true);
|
||||
TESTASSERT(srsran_sampling_freq_hz(6) == 1920000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(15) == 3840000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(25) == 7680000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(50) == 15360000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(75) == 23040000);
|
||||
TESTASSERT(srsran_sampling_freq_hz(100) == 30720000);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TESTASSERT(srsran_default_rates_test() == SRSRAN_SUCCESS);
|
||||
TESTASSERT(lte_standard_rates_test() == SRSRAN_SUCCESS);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
|
@ -711,7 +711,8 @@ int srsran_ofdm_set_cfr(srsran_ofdm_t* q, srsran_cfr_cfg_t* cfr)
|
|||
q->cfg.cfr_tx_cfg.symbol_sz = q->cfg.symbol_sz;
|
||||
q->cfg.cfr_tx_cfg.symbol_bw = q->nof_re;
|
||||
|
||||
// in the DL, the DC carrier is empty but still counts when designing the filter BW
|
||||
// in the LTE DL, the DC carrier is empty but still counts when designing the filter BW
|
||||
// in the LTE UL, the DC carrier is used
|
||||
q->cfg.cfr_tx_cfg.dc_sc = (!q->cfg.keep_dc) && (!isnormal(q->cfg.freq_shift_f));
|
||||
if (q->cfg.cfr_tx_cfg.cfr_enable) {
|
||||
if (srsran_cfr_init(&q->tx_cfr, &q->cfg.cfr_tx_cfg) < SRSRAN_SUCCESS) {
|
||||
|
|
|
@ -193,7 +193,9 @@ static int get_pucch(srsran_enb_ul_t* q, srsran_ul_sf_cfg_t* ul_sf, srsran_pucch
|
|||
ERROR("Error estimating PUCCH DMRS");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
pucch_res.snr_db = q->chest_res.snr_db;
|
||||
pucch_res.snr_db = q->chest_res.snr_db;
|
||||
pucch_res.rssi_dbFs = q->chest_res.epre_dBfs;
|
||||
pucch_res.ni_dbFs = q->chest_res.noise_estimate_dbFs;
|
||||
|
||||
ret = srsran_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, &pucch_res);
|
||||
if (ret < SRSRAN_SUCCESS) {
|
||||
|
|
|
@ -317,7 +317,7 @@ int srsran_gnb_ul_get_pucch(srsran_gnb_ul_t* q,
|
|||
meas->epre = q->chest_pucch.epre;
|
||||
meas->epre_dB = q->chest_pucch.epre_dBfs;
|
||||
meas->n0 = q->chest_pucch.noise_estimate;
|
||||
meas->n0_dB = q->chest_pucch.noise_estimate_dbm;
|
||||
meas->n0_dB = q->chest_pucch.noise_estimate_dbFs;
|
||||
meas->snr_dB = q->chest_pucch.snr_db;
|
||||
meas->cfo_hz = q->chest_pucch.cfo_hz;
|
||||
meas->cfo_hz_max = NAN; // Unavailable
|
||||
|
|
|
@ -88,6 +88,7 @@ static int harq_ack_gen_ack_type2(const srsran_harq_ack_cfg_hl_t* cfg,
|
|||
if (ack->present) {
|
||||
// Load ACK resource data into UCI info
|
||||
uci_cfg->pucch.resource_id = ack_info->cc[c].m[m].resource.pucch_resource_id;
|
||||
uci_cfg->pucch.n_cce_0 = ack_info->cc[c].m[m].resource.n_cce;
|
||||
uci_cfg->pucch.rnti = ack_info->cc[c].m[m].resource.rnti;
|
||||
|
||||
if (V_DL_CDAI <= V_temp) {
|
||||
|
@ -183,6 +184,7 @@ int srsran_harq_ack_resource(const srsran_harq_ack_cfg_hl_t* cfg,
|
|||
pdsch_ack_resource->v_dai_dl = dci_dl->dai;
|
||||
pdsch_ack_resource->rnti = dci_dl->ctx.rnti;
|
||||
pdsch_ack_resource->pucch_resource_id = dci_dl->pucch_resource;
|
||||
pdsch_ack_resource->n_cce = dci_dl->ctx.location.ncce;
|
||||
pdsch_ack_resource->pid = dci_dl->pid;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
|
|
@ -169,7 +169,8 @@ int srsran_pucch_nr_cfg_resource_valid(const srsran_pucch_nr_resource_t* resourc
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (resource->intra_slot_hopping) {
|
||||
// Frequency hopping is only possible with Format 1
|
||||
if (resource->intra_slot_hopping && resource->format != SRSRAN_PUCCH_NR_FORMAT_1) {
|
||||
ERROR("Intra-slot hopping is not implemented");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
|
|
@ -406,6 +406,8 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q,
|
|||
srsran_mod_modulate(&q->qpsk, b, d, 2);
|
||||
}
|
||||
|
||||
INFO("[PUCCH Format 1 Data TX] d=%+.3f%+.3f", __real__ d[0], __imag__ d[0]);
|
||||
|
||||
// Get group sequence
|
||||
uint32_t u = 0;
|
||||
uint32_t v = 0;
|
||||
|
@ -414,41 +416,60 @@ int srsran_pucch_nr_format1_encode(const srsran_pucch_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0);
|
||||
|
||||
// First symbol of this PUCCH transmission
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) {
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
// For each hop
|
||||
for (uint32_t m_prime = 0, l = 1; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, m_prime);
|
||||
|
||||
// Get the starting PRB
|
||||
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||
|
||||
// For each symbol carrying PUCCH data
|
||||
for (uint32_t m = 0; m < n_pucch; m++, l += 2) {
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, 0, &alpha_idx) <
|
||||
SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 Data TX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f z=",
|
||||
m_prime,
|
||||
m,
|
||||
__real__ w_i_m,
|
||||
__imag__ w_i_m);
|
||||
srsran_vec_fprint_c(stdout, z, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// Put z in the grid
|
||||
srsran_vec_sc_prod_ccc(z, d[0], slot_symbols_ptr, SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 TX] l=%d; x=", l + l_prime);
|
||||
srsran_vec_fprint_c(stdout, slot_symbols_ptr, SRSRAN_NRE);
|
||||
}
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Compute y = d(0) * r_uv
|
||||
cf_t y[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, d[0], y, SRSRAN_NRE);
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * y(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(y, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
// Put z in the grid
|
||||
srsran_vec_cf_copy(slot_symbols_ptr, z, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
|
@ -493,46 +514,79 @@ int srsran_pucch_nr_format1_decode(srsran_pucch_nr_t* q,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, 0);
|
||||
|
||||
// First symbol of this PUCCH transmission
|
||||
uint32_t l_prime = resource->start_symbol_idx;
|
||||
for (uint32_t l = 1, m = 0; l < resource->nof_symbols; l += 2, m++) {
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
cf_t* ce_ptr = &chest_res->ce[(q->carrier.nof_prb * (l + l_prime) + resource->starting_prb) * SRSRAN_NRE];
|
||||
|
||||
// Equalise x = w(i) * d' * r_uv(n)
|
||||
cf_t x[SRSRAN_NRE];
|
||||
srsran_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSRAN_NRE, 1.0f, chest_res->noise_estimate);
|
||||
// For each hop
|
||||
uint32_t n_pucch_sum = 0;
|
||||
for (uint32_t m_prime = 0, l = 1; m_prime < (resource->intra_slot_hopping ? 2 : 1); m_prime++) {
|
||||
// Calculate number of symbols carrying PUCCH (No DMRS)
|
||||
uint32_t n_pucch = pucch_nr_format1_n_pucch(resource, m_prime);
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(
|
||||
&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
// Get the starting PRB
|
||||
uint32_t starting_prb = (m_prime == 0) ? resource->starting_prb : resource->second_hop_prb;
|
||||
|
||||
// For each symbol carrying PUCCH data
|
||||
for (uint32_t m = 0; m < n_pucch; m++, l += 2) {
|
||||
// Get start of the sequence in resource grid
|
||||
cf_t* slot_symbols_ptr = &slot_symbols[(q->carrier.nof_prb * (l + l_prime) + starting_prb) * SRSRAN_NRE];
|
||||
cf_t* ce_ptr = &chest_res->ce[SRSRAN_NRE * n_pucch_sum];
|
||||
n_pucch_sum++;
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 CE RX] ce=");
|
||||
srsran_vec_fprint_c(stdout, ce_ptr, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// Equalise x = w(i) * d' * r_uv(n)
|
||||
cf_t x[SRSRAN_NRE];
|
||||
srsran_predecoding_single(slot_symbols_ptr, ce_ptr, x, NULL, SRSRAN_NRE, 1.0f, chest_res->noise_estimate);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 RX] l=%d; x=", l + l_prime);
|
||||
srsran_vec_fprint_c(stdout, x, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// Get Alpha index
|
||||
uint32_t alpha_idx = 0;
|
||||
if (srsran_pucch_nr_alpha_idx(
|
||||
&q->carrier, cfg, slot, l, l_prime, resource->initial_cyclic_shift, m_cs, &alpha_idx) < SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
if (SRSRAN_DEBUG_ENABLED && get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO && !is_handler_registered()) {
|
||||
printf("[PUCCH Format 1 Data RX] m_prime=%d; m=%d; w_i_m=%+.3f%+.3f z=",
|
||||
m_prime,
|
||||
m,
|
||||
__real__ w_i_m,
|
||||
__imag__ w_i_m);
|
||||
srsran_vec_fprint_c(stdout, z, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d'
|
||||
d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE) / SRSRAN_NRE;
|
||||
|
||||
// Compute and accumulate average symbol power
|
||||
pwr_acc += srsran_vec_avg_power_cf(x, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
// get r_uv sequence from LUT object
|
||||
const cf_t* r_uv = srsran_zc_sequence_lut_get(&q->r_uv_1prb, u, v, alpha_idx);
|
||||
if (r_uv == NULL) {
|
||||
ERROR("Getting r_uv sequence");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
// Get w_i_m
|
||||
cf_t w_i_m = srsran_pucch_nr_format1_w(q, n_pucch, resource->time_domain_occ, m);
|
||||
|
||||
// Compute z(n) = w(i) * r_uv(n)
|
||||
cf_t z[SRSRAN_NRE];
|
||||
srsran_vec_sc_prod_ccc(r_uv, w_i_m, z, SRSRAN_NRE);
|
||||
|
||||
// Compute d = sum(x * conj(w(i) * r_uv(n))) = sum(w(i) * d' * r_uv(n) * conj(w(i) * r_uv(n))) = d'
|
||||
d += srsran_vec_dot_prod_conj_ccc(x, z, SRSRAN_NRE) / SRSRAN_NRE;
|
||||
|
||||
// Compute and accumulate average symbol power
|
||||
pwr_acc += srsran_vec_avg_power_cf(x, SRSRAN_NRE);
|
||||
}
|
||||
|
||||
INFO("[PUCCH Format 1 Data RX] d=%+.3f%+.3f", __real__ d, __imag__ d);
|
||||
|
||||
// Demodulate d
|
||||
float llr[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||
srsran_demod_soft_demodulate((nof_bits == 1) ? SRSRAN_MOD_BPSK : SRSRAN_MOD_QPSK, &d, llr, 1);
|
||||
|
|
|
@ -479,11 +479,89 @@ int srsran_ra_ul_nr_freq(const srsran_carrier_nr_t* carrier,
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
srsran_pucch_nr_format_t format;
|
||||
uint32_t start_symbol;
|
||||
uint32_t rb_offset;
|
||||
uint32_t N_cs;
|
||||
} pucch_res_common_cfg_t;
|
||||
|
||||
// Table 9.2.1-1
|
||||
#define PUCCH_RES_COMMON_CFG_IDX_MAX 15
|
||||
static pucch_res_common_cfg_t pucch_res_common_cfg[PUCCH_RES_COMMON_CFG_IDX_MAX + 1] = {
|
||||
{SRSRAN_PUCCH_NR_FORMAT_0, 12, 0, 2},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_0, 12, 0, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_0, 12, 3, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 10, 0, 2},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 10, 0, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 10, 2, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 10, 4, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 4, 0, 2},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 4, 0, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 4, 2, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 4, 4, 3},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 0, 0, 2},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 0, 0, 4},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 0, 2, 4},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 0, 4, 4},
|
||||
{SRSRAN_PUCCH_NR_FORMAT_1, 0, 0, 4}};
|
||||
|
||||
// Implements TS 38.213 Table 9.2.1-1: PUCCH resource sets before dedicated PUCCH resource configuration
|
||||
static int ra_ul_nr_pucch_resource_default(uint32_t r_pucch, srsran_pucch_nr_resource_t* resource)
|
||||
static int ra_ul_nr_pucch_resource_default(uint32_t pucch_res_common_idx,
|
||||
uint32_t N_size_bwp,
|
||||
uint32_t r_pucch,
|
||||
srsran_pucch_nr_resource_t* resource)
|
||||
{
|
||||
ERROR("Not implemented");
|
||||
return SRSRAN_ERROR;
|
||||
if (pucch_res_common_idx > PUCCH_RES_COMMON_CFG_IDX_MAX) {
|
||||
ERROR("Invalid pucch_res_common_idx value (%d)\n", pucch_res_common_idx);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
uint32_t cs_v_2[2] = {0, 6};
|
||||
uint32_t cs_v_3[3] = {0, 4, 8};
|
||||
uint32_t cs_v_4[4] = {0, 3, 6, 9};
|
||||
|
||||
// Table 9.2.1-1
|
||||
resource->format = pucch_res_common_cfg[pucch_res_common_idx].format;
|
||||
resource->start_symbol_idx = pucch_res_common_cfg[pucch_res_common_idx].start_symbol;
|
||||
resource->nof_symbols = 14 - resource->start_symbol_idx;
|
||||
uint32_t rb_offset_bwp = pucch_res_common_cfg[pucch_res_common_idx].rb_offset;
|
||||
uint32_t N_cs = pucch_res_common_cfg[pucch_res_common_idx].N_cs;
|
||||
|
||||
// Special case for cs_v_2 value
|
||||
if (pucch_res_common_idx == 0) {
|
||||
cs_v_2[1] = 3;
|
||||
}
|
||||
|
||||
// Special case for rb_offset
|
||||
if (pucch_res_common_idx == 15) {
|
||||
rb_offset_bwp = N_size_bwp / 4;
|
||||
}
|
||||
|
||||
uint32_t csv_idx = 0;
|
||||
if (r_pucch / 8 == 0) {
|
||||
resource->starting_prb = rb_offset_bwp + SRSRAN_FLOOR(r_pucch, N_cs);
|
||||
resource->second_hop_prb = N_size_bwp - 1 - resource->starting_prb;
|
||||
csv_idx = r_pucch % N_cs;
|
||||
} else {
|
||||
resource->second_hop_prb = rb_offset_bwp + SRSRAN_FLOOR(r_pucch - 8, N_cs);
|
||||
resource->starting_prb = N_size_bwp - 1 - resource->second_hop_prb;
|
||||
csv_idx = (r_pucch - 8) % N_cs;
|
||||
}
|
||||
|
||||
switch (N_cs) {
|
||||
case 2:
|
||||
resource->initial_cyclic_shift = cs_v_2[csv_idx];
|
||||
break;
|
||||
case 3:
|
||||
resource->initial_cyclic_shift = cs_v_3[csv_idx];
|
||||
break;
|
||||
case 4:
|
||||
resource->initial_cyclic_shift = cs_v_4[csv_idx];
|
||||
break;
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
static int ra_ul_nr_pucch_resource_hl(const srsran_pucch_nr_hl_cfg_t* cfg,
|
||||
|
@ -531,6 +609,7 @@ static int ra_ul_nr_pucch_resource_hl(const srsran_pucch_nr_hl_cfg_t* cfg,
|
|||
|
||||
int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
||||
const srsran_uci_cfg_nr_t* uci_cfg,
|
||||
uint32_t N_bwp_sz,
|
||||
srsran_pucch_nr_resource_t* resource)
|
||||
{
|
||||
if (pucch_cfg == NULL || uci_cfg == NULL || resource == NULL) {
|
||||
|
@ -632,8 +711,9 @@ int srsran_ra_ul_nr_pucch_resource(const srsran_pucch_nr_hl_cfg_t* pucch_cfg,
|
|||
// a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size
|
||||
// transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs.
|
||||
if (!pucch_cfg->enabled) {
|
||||
uint32_t r_pucch = (2 * uci_cfg->pucch.n_cce_0) + 2 * uci_cfg->pucch.resource_id;
|
||||
return ra_ul_nr_pucch_resource_default(r_pucch, resource);
|
||||
uint32_t N_cce = SRSRAN_FLOOR(N_bwp_sz, 6);
|
||||
uint32_t r_pucch = ((2 * uci_cfg->pucch.n_cce_0) / N_cce) + 2 * uci_cfg->pucch.resource_id;
|
||||
return ra_ul_nr_pucch_resource_default(pucch_cfg->common.resource_common, N_bwp_sz, r_pucch, resource);
|
||||
}
|
||||
return ra_ul_nr_pucch_resource_hl(pucch_cfg, uci_cfg, uci_cfg->pucch.resource_id, resource);
|
||||
}
|
||||
|
|
|
@ -57,15 +57,15 @@ add_executable(psbch_file_test psbch_file_test.c)
|
|||
target_link_libraries(psbch_file_test srsran_phy)
|
||||
|
||||
# TM2 file tests
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p6_c0 psbch_file_test -p 6 -c 0 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p15_c84 psbch_file_test -p 15 -c 84 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p25_c168 psbch_file_test -p 25 -c 168 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p50_c252 psbch_file_test -p 50 -c 252 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p100_c335 psbch_file_test -p 100 -c 335 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p50_c252_ext psbch_file_test -p 50 -c 252 -e -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6_ext.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p6_c0 psbch_file_test -p 6 -c 0 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p15_c84 psbch_file_test -p 15 -c 84 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p25_c168 psbch_file_test -p 25 -c 168 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p50_c252 psbch_file_test -p 50 -c 252 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p100_c335 psbch_file_test -p 100 -c 335 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
add_lte_test(psbch_file_test_ideal_tm2_p50_c252_ext psbch_file_test -p 50 -c 252 -e -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p50_c252_s15.36e6_ext.dat)
|
||||
|
||||
# TM4 file tests
|
||||
add_lte_test(psbch_file_test_cmw_tm4_p50_c169 psbch_file_test -p 50 -c 169 -t 4 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_slss_id169.dat)
|
||||
add_lte_test(psbch_file_test_cmw_tm4_p50_c169 psbch_file_test -p 50 -c 169 -t 4 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_slss_id169.dat)
|
||||
|
||||
########################################################################
|
||||
# PSCCH TEST
|
||||
|
@ -123,38 +123,38 @@ add_executable(pssch_pscch_file_test pssch_pscch_file_test.c)
|
|||
target_link_libraries(pssch_pscch_file_test srsran_phy)
|
||||
|
||||
# TM2 file tests
|
||||
add_lte_test(pssch_pscch_file_test_ideal_tm2_p100 pssch_pscch_file_test -p 100 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
add_lte_test(pssch_pscch_file_test_ideal_tm2_p100 pssch_pscch_file_test -p 100 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
set_property(TEST pssch_pscch_file_test_ideal_tm2_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=[2,3] num_decoded_tb=1")
|
||||
|
||||
# TM4 file tests (first SF is sf_idx = 6 such that the PSSCH sf_idx=0)
|
||||
add_lte_test(pssch_pscch_file_test_ideal_tm4_p100 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -d -m 6 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat)
|
||||
add_lte_test(pssch_pscch_file_test_ideal_tm4_p100 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -d -m 6 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat)
|
||||
set_property(TEST pssch_pscch_file_test_ideal_tm4_p100 PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1")
|
||||
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_qc pssch_pscch_file_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_qc pssch_pscch_file_test -p 50 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_qc9150_f5.92e9_s15.36e6_50prb_20offset.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p50_qc PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1 num_decoded_tb=1")
|
||||
|
||||
# Capture has a SFO offset of ~64 samples, but offsetting by 20 is enough to decode it
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_cmw pssch_pscch_file_test -p 50 -t 4 -o 20 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_cmw pssch_pscch_file_test -p 50 -t 4 -o 20 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_cmw500_f5.92e9_s11.52e6_50prb_0offset_1ms.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p50_cmw PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=1 num_decoded_tb=1")
|
||||
|
||||
# With PHY retransmission (3 TTI offset) first SF at sf_idx=5
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_huawei pssch_pscch_file_test -p 50 -t 4 -m 5 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_huawei pssch_pscch_file_test -p 50 -t 4 -m 5 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_huawei_s11.52e6_50prb_10prb_offset_with_retx.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p50_huawei PROPERTY PASS_REGULAR_EXPRESSION "num_decoded_sci=2 num_decoded_tb=2")
|
||||
|
||||
# With PHY ReTx (0 TTI offset?)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_uxm1 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_uxm1 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs12.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p50_uxm1 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=2 num_decoded_tb=2")
|
||||
|
||||
# 100 PRB startOffset 1 MCS12 MAC padding, first SF is index 0
|
||||
add_lte_test(pssch_pscch_test_tm4_p100_uxm2 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p100_uxm2 pssch_pscch_file_test -p 100 -t 4 -s 10 -n 10 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_uxm_s23.04e6_100prb_1prb_offset_mcs12_padding.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p100_uxm2 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=4")
|
||||
|
||||
# 100 PRB LTE sampling rate, startOffset1 MCS12 ITS data, first SF is index 6
|
||||
add_lte_test(pssch_pscch_test_tm4_p100_uxm3 pssch_pscch_file_test -p 100 -d -t 4 -s 10 -n 10 -m 6 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p100_uxm3 pssch_pscch_file_test -p 100 -d -t 4 -s 10 -n 10 -m 6 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_uxm_s30.72e6_100prb_1prb_offset_mcs12_its.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p100_uxm3 PROPERTY PASS_REGULAR_EXPRESSION "mcs=12.*num_decoded_sci=1")
|
||||
|
||||
# 50 PRB LTE sampling rate, startOffset0 MCS28 MAC padding, first SF is index 1
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_uxm4 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -m 1 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat)
|
||||
add_lte_test(pssch_pscch_test_tm4_p50_uxm4 pssch_pscch_file_test -p 50 -d -t 4 -s 5 -n 10 -m 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal_sidelink_uxm_s15.36e6_50prb_0prb_offset_mcs28_padding_5ms.dat)
|
||||
set_property(TEST pssch_pscch_test_tm4_p50_uxm4 PROPERTY PASS_REGULAR_EXPRESSION "mcs=28.*num_decoded_sci=5")
|
||||
|
||||
########################################################################
|
||||
|
|
|
@ -88,63 +88,71 @@ static int test_pucch_format0(srsran_pucch_nr_t* pucch, const srsran_pucch_nr_co
|
|||
static int test_pucch_format1(srsran_pucch_nr_t* pucch,
|
||||
const srsran_pucch_nr_common_cfg_t* cfg,
|
||||
srsran_chest_ul_res_t* chest_res,
|
||||
cf_t* slot_symbols)
|
||||
cf_t* slot_symbols,
|
||||
bool enable_intra_slot_hopping)
|
||||
{
|
||||
srsran_slot_cfg_t slot = {};
|
||||
srsran_pucch_nr_resource_t resource = {};
|
||||
resource.format = SRSRAN_PUCCH_NR_FORMAT_1;
|
||||
resource.intra_slot_hopping = enable_intra_slot_hopping;
|
||||
|
||||
for (slot.idx = 0; slot.idx < SRSRAN_NSLOTS_PER_FRAME_NR(carrier.scs); slot.idx++) {
|
||||
for (resource.starting_prb = 0; resource.starting_prb < carrier.nof_prb;
|
||||
resource.starting_prb += starting_prb_stride) {
|
||||
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB;
|
||||
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB;
|
||||
resource.nof_symbols++) {
|
||||
for (resource.start_symbol_idx = 0;
|
||||
resource.start_symbol_idx <=
|
||||
SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols);
|
||||
resource.start_symbol_idx += starting_symbol_stride) {
|
||||
for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC;
|
||||
resource.time_domain_occ++) {
|
||||
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS;
|
||||
resource.initial_cyclic_shift++) {
|
||||
for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) {
|
||||
for (uint32_t word = 0; word < (1U << nof_bits); word++) {
|
||||
// Generate bits
|
||||
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
b[i] = (word >> i) & 1U;
|
||||
}
|
||||
for (resource.second_hop_prb = 0; resource.second_hop_prb < (enable_intra_slot_hopping) ? carrier.nof_prb : 0;
|
||||
resource.second_hop_prb += starting_prb_stride) {
|
||||
for (resource.nof_symbols = SRSRAN_PUCCH_NR_FORMAT1_MIN_NSYMB;
|
||||
resource.nof_symbols <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NSYMB;
|
||||
resource.nof_symbols++) {
|
||||
for (resource.start_symbol_idx = 0;
|
||||
resource.start_symbol_idx <=
|
||||
SRSRAN_MIN(SRSRAN_PUCCH_NR_FORMAT1_MAX_STARTSYMB, SRSRAN_NSYMB_PER_SLOT_NR - resource.nof_symbols);
|
||||
resource.start_symbol_idx += starting_symbol_stride) {
|
||||
for (resource.time_domain_occ = 0; resource.time_domain_occ <= SRSRAN_PUCCH_NR_FORMAT1_MAX_TOCC;
|
||||
resource.time_domain_occ++) {
|
||||
for (resource.initial_cyclic_shift = 0; resource.initial_cyclic_shift <= SRSRAN_PUCCH_NR_FORMAT1_MAX_CS;
|
||||
resource.initial_cyclic_shift++) {
|
||||
for (uint32_t nof_bits = 1; nof_bits <= SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS; nof_bits++) {
|
||||
for (uint32_t word = 0; word < (1U << nof_bits); word++) {
|
||||
// Generate bits
|
||||
uint8_t b[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {};
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
b[i] = (word >> i) & 1U;
|
||||
}
|
||||
|
||||
// Encode PUCCH
|
||||
TESTASSERT(srsran_pucch_nr_format1_encode(pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) ==
|
||||
SRSRAN_SUCCESS);
|
||||
// Encode PUCCH
|
||||
TESTASSERT(srsran_pucch_nr_format1_encode(
|
||||
pucch, cfg, &slot, &resource, b, nof_bits, slot_symbols) == SRSRAN_SUCCESS);
|
||||
|
||||
// Put DMRS
|
||||
TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
|
||||
SRSRAN_SUCCESS);
|
||||
// Put DMRS
|
||||
TESTASSERT(srsran_dmrs_pucch_format1_put(pucch, &carrier, cfg, &slot, &resource, slot_symbols) ==
|
||||
SRSRAN_SUCCESS);
|
||||
|
||||
// Apply AWGN
|
||||
srsran_channel_awgn_run_c(
|
||||
&awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR);
|
||||
// Apply AWGN
|
||||
srsran_channel_awgn_run_c(
|
||||
&awgn, slot_symbols, slot_symbols, carrier.nof_prb * SRSRAN_NRE * SRSRAN_NSYMB_PER_SLOT_NR);
|
||||
|
||||
// Estimate channel
|
||||
TESTASSERT(srsran_dmrs_pucch_format1_estimate(
|
||||
pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS);
|
||||
// Estimate channel
|
||||
TESTASSERT(srsran_dmrs_pucch_format1_estimate(
|
||||
pucch, cfg, &slot, &resource, slot_symbols, chest_res) == SRSRAN_SUCCESS);
|
||||
|
||||
TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f);
|
||||
TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f);
|
||||
TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f);
|
||||
TESTASSERT(fabsf(chest_res->rsrp_dBfs - 0.0f) < 3.0f);
|
||||
TESTASSERT(fabsf(chest_res->epre_dBfs - 0.0f) < 3.0f);
|
||||
TESTASSERT(fabsf(chest_res->snr_db - snr_db) < 10.0f);
|
||||
|
||||
// Decode PUCCH
|
||||
uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||
TESTASSERT(srsran_pucch_nr_format1_decode(
|
||||
pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) ==
|
||||
SRSRAN_SUCCESS);
|
||||
// Decode PUCCH
|
||||
uint8_t b_rx[SRSRAN_PUCCH_NR_FORMAT1_MAX_NOF_BITS];
|
||||
TESTASSERT(srsran_pucch_nr_format1_decode(
|
||||
pucch, cfg, &slot, &resource, chest_res, slot_symbols, b_rx, nof_bits, NULL) ==
|
||||
SRSRAN_SUCCESS);
|
||||
|
||||
// Check received bits
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
TESTASSERT(b[i] == b_rx[i]);
|
||||
// Check received bits
|
||||
for (uint32_t i = 0; i < nof_bits; i++) {
|
||||
if (b[i] != b_rx[i]) {
|
||||
printf("aaa");
|
||||
}
|
||||
TESTASSERT(b[i] == b_rx[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,9 +353,13 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
// Test Format 1
|
||||
// Test Format 1 with and without intra slot frequency hopping
|
||||
if (format < 0 || format == 1) {
|
||||
if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb) < SRSRAN_SUCCESS) {
|
||||
if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb, false) < SRSRAN_SUCCESS) {
|
||||
ERROR("Failed PUCCH format 1");
|
||||
goto clean_exit;
|
||||
}
|
||||
if (test_pucch_format1(&pucch, &common_cfg, &chest_res, slot_symb, true) < SRSRAN_SUCCESS) {
|
||||
ERROR("Failed PUCCH format 1");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
|
|
@ -23,13 +23,32 @@ if(RF_FOUND)
|
|||
add_library(srsran_rf_utils STATIC rf_utils.c)
|
||||
target_link_libraries(srsran_rf_utils srsran_phy)
|
||||
|
||||
# Include common RF files
|
||||
# Top-level RF library sources
|
||||
set(SOURCES_RF "")
|
||||
list(APPEND SOURCES_RF rf_imp.c)
|
||||
|
||||
if (UHD_FOUND)
|
||||
# Lists of static (builtin) and dynamic RF plugins
|
||||
set(STATIC_PLUGINS "")
|
||||
set(DYNAMIC_PLUGINS "")
|
||||
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_definitions(-DENABLE_RF_PLUGINS)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
|
||||
# RF plugins
|
||||
if (UHD_FOUND AND ENABLE_UHD)
|
||||
add_definitions(-DENABLE_UHD)
|
||||
list(APPEND SOURCES_RF rf_uhd_imp.cc)
|
||||
set(SOURCES_UHD rf_uhd_imp.cc)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_uhd SHARED ${SOURCES_UHD})
|
||||
set_target_properties(srsran_rf_uhd PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
list(APPEND DYNAMIC_PLUGINS srsran_rf_uhd)
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_uhd STATIC ${SOURCES_UHD})
|
||||
list(APPEND STATIC_PLUGINS srsran_rf_uhd)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
target_link_libraries(srsran_rf_uhd srsran_rf_utils srsran_phy ${UHD_LIBRARIES} ${Boost_LIBRARIES})
|
||||
install(TARGETS srsran_rf_uhd DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
||||
# If found, add a macro to inform the UHD driver about the available feature
|
||||
if (UHD_ENABLE_X300_FW_RESET)
|
||||
|
@ -41,72 +60,117 @@ if(RF_FOUND)
|
|||
if (UHD_ENABLE_CUSTOM_RFNOC)
|
||||
add_definitions(-DUHD_ENABLE_CUSTOM_RFNOC)
|
||||
endif(UHD_ENABLE_CUSTOM_RFNOC)
|
||||
endif (UHD_FOUND)
|
||||
endif (UHD_FOUND AND ENABLE_UHD)
|
||||
|
||||
if (BLADERF_FOUND AND ENABLE_BLADERF)
|
||||
add_definitions(-DENABLE_BLADERF)
|
||||
set(SOURCES_BLADE rf_blade_imp.c)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_blade SHARED ${SOURCES_BLADE})
|
||||
set_target_properties(srsran_rf_blade PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
list(APPEND DYNAMIC_PLUGINS srsran_rf_blade)
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_blade STATIC ${SOURCES_BLADE})
|
||||
list(APPEND STATIC_PLUGINS srsran_rf_blade)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
target_link_libraries(srsran_rf_blade srsran_rf_utils srsran_phy ${BLADERF_LIBRARIES})
|
||||
install(TARGETS srsran_rf_blade DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endif (BLADERF_FOUND AND ENABLE_BLADERF)
|
||||
|
||||
if (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
add_definitions(-DENABLE_SOAPYSDR)
|
||||
set(SOURCES_SOAPY rf_soapy_imp.c)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_soapy SHARED ${SOURCES_SOAPY})
|
||||
set_target_properties(srsran_rf_soapy PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
list(APPEND DYNAMIC_PLUGINS srsran_rf_soapy)
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_soapy STATIC ${SOURCES_SOAPY})
|
||||
list(APPEND STATIC_PLUGINS srsran_rf_soapy)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
target_link_libraries(srsran_rf_soapy srsran_rf_utils srsran_phy ${SOAPYSDR_LIBRARIES})
|
||||
install(TARGETS srsran_rf_soapy DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endif (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
|
||||
if(SKIQ_FOUND AND ENABLE_SKIQ)
|
||||
add_executable(skiq_pps_test skiq_pps_test.c)
|
||||
target_link_libraries(skiq_pps_test ${SKIQ_LIBRARIES} rt pthread m)
|
||||
add_definitions(-DENABLE_SIDEKIQ)
|
||||
set(SOURCES_SKIQ rf_skiq_imp.c rf_skiq_imp_card.c rf_skiq_imp_port.c)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_skiq SHARED ${SOURCES_SKIQ})
|
||||
set_target_properties(srsran_rf_skiq PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
list(APPEND DYNAMIC_PLUGINS srsran_rf_skiq)
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_skiq STATIC ${SOURCES_SKIQ})
|
||||
list(APPEND STATIC_PLUGINS srsran_rf_skiq)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
target_link_libraries(srsran_rf_skiq srsran_rf_utils srsran_phy ${SKIQ_LIBRARIES} rt)
|
||||
install(TARGETS srsran_rf_skiq DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endif(SKIQ_FOUND AND ENABLE_SKIQ)
|
||||
|
||||
if (ZEROMQ_FOUND AND ENABLE_ZEROMQ)
|
||||
add_definitions(-DENABLE_ZEROMQ)
|
||||
set(SOURCES_ZMQ rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_zmq SHARED ${SOURCES_ZMQ})
|
||||
set_target_properties(srsran_rf_zmq PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
list(APPEND DYNAMIC_PLUGINS srsran_rf_zmq)
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
add_library(srsran_rf_zmq STATIC ${SOURCES_ZMQ})
|
||||
list(APPEND STATIC_PLUGINS srsran_rf_zmq)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
target_link_libraries(srsran_rf_zmq srsran_rf_utils srsran_phy ${ZEROMQ_LIBRARIES})
|
||||
install(TARGETS srsran_rf_zmq DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endif (ZEROMQ_FOUND AND ENABLE_ZEROMQ)
|
||||
|
||||
# Add sources of file-based RF directly to the RF library (not as a plugin)
|
||||
list(APPEND SOURCES_RF rf_file_imp.c rf_file_imp_tx.c rf_file_imp_rx.c)
|
||||
|
||||
# Top-level RF library
|
||||
add_library(srsran_rf_object OBJECT ${SOURCES_RF})
|
||||
set_property(TARGET srsran_rf_object PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
set(TOP_RF_LIBS)
|
||||
if (ENABLE_RF_PLUGINS)
|
||||
# Build as shared library with optional RF plugins (optional dependencies)
|
||||
if (DYNAMIC_PLUGINS)
|
||||
add_dependencies(srsran_rf_object ${DYNAMIC_PLUGINS})
|
||||
endif (DYNAMIC_PLUGINS)
|
||||
add_library(srsran_rf SHARED $<TARGET_OBJECTS:srsran_rf_object>)
|
||||
target_link_libraries(srsran_rf dl)
|
||||
list(APPEND TOP_RF_LIBS srsran_rf)
|
||||
|
||||
# Add $ORIGIN (i.e. current location of this library) to rpath of srsran_rf.
|
||||
# This ensures that it will find the plugins that reside in the same directory as the library
|
||||
set_target_properties(srsran_rf PROPERTIES BUILD_RPATH "\$ORIGIN/")
|
||||
set_target_properties(srsran_rf PROPERTIES INSTALL_RPATH "\$ORIGIN/")
|
||||
else (ENABLE_RF_PLUGINS)
|
||||
# Build as static library with built-in RF plugins (mandatory dependencies)
|
||||
add_library(srsran_rf STATIC $<TARGET_OBJECTS:srsran_rf_object>)
|
||||
target_link_libraries(srsran_rf ${STATIC_PLUGINS})
|
||||
list(APPEND TOP_RF_LIBS srsran_rf)
|
||||
|
||||
# Also build as shared library with built-in RF plugins (mandatory dependencies)
|
||||
add_library(srsran_rf_shared SHARED $<TARGET_OBJECTS:srsran_rf_object>)
|
||||
target_link_libraries(srsran_rf_shared ${STATIC_PLUGINS})
|
||||
list(APPEND TOP_RF_LIBS srsran_rf_shared)
|
||||
set_target_properties(srsran_rf_shared PROPERTIES OUTPUT_NAME srsran_rf)
|
||||
endif (ENABLE_RF_PLUGINS)
|
||||
|
||||
foreach (TOP_RF_LIB ${TOP_RF_LIBS})
|
||||
target_link_libraries(${TOP_RF_LIB} srsran_rf_utils srsran_phy)
|
||||
set_target_properties(${TOP_RF_LIB} PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
install(TARGETS ${TOP_RF_LIB} DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endforeach ()
|
||||
|
||||
# Tests
|
||||
if (UHD_FOUND AND UHD_ENABLE_CUSTOM_RFNOC)
|
||||
add_executable(rfnoc_test rfnoc_test.cc)
|
||||
target_link_libraries(rfnoc_test srsran_rf ${UHD_LIBRARIES} ${Boost_LIBRARIES} /usr/lib/x86_64-linux-gnu/libboost_system.so)
|
||||
message(info ${Boost_LIBRARIES})
|
||||
endif (UHD_FOUND AND UHD_ENABLE_CUSTOM_RFNOC)
|
||||
|
||||
if (BLADERF_FOUND)
|
||||
add_definitions(-DENABLE_BLADERF)
|
||||
list(APPEND SOURCES_RF rf_blade_imp.c)
|
||||
endif (BLADERF_FOUND)
|
||||
|
||||
if (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
add_definitions(-DENABLE_SOAPYSDR)
|
||||
list(APPEND SOURCES_RF rf_soapy_imp.c)
|
||||
endif (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
|
||||
if(SKIQ_FOUND)
|
||||
add_executable(skiq_pps_test skiq_pps_test.c)
|
||||
target_link_libraries(skiq_pps_test ${SKIQ_LIBRARIES} rt pthread m)
|
||||
add_definitions(-DENABLE_SIDEKIQ)
|
||||
list(APPEND SOURCES_RF rf_skiq_imp.c rf_skiq_imp_card.c rf_skiq_imp_port.c)
|
||||
endif(SKIQ_FOUND)
|
||||
|
||||
if (ZEROMQ_FOUND)
|
||||
add_definitions(-DENABLE_ZEROMQ)
|
||||
list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c)
|
||||
endif (ZEROMQ_FOUND)
|
||||
|
||||
list(APPEND SOURCES_RF rf_file_imp.c rf_file_imp_tx.c rf_file_imp_rx.c)
|
||||
|
||||
add_library(srsran_rf_object OBJECT ${SOURCES_RF})
|
||||
set_property(TARGET srsran_rf_object PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
|
||||
add_library(srsran_rf STATIC $<TARGET_OBJECTS:srsran_rf_object>)
|
||||
add_library(srsran_rf_shared SHARED $<TARGET_OBJECTS:srsran_rf_object>)
|
||||
|
||||
target_link_libraries(srsran_rf srsran_rf_utils srsran_phy)
|
||||
set_target_properties(srsran_rf PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
target_link_libraries(srsran_rf_shared srsran_rf_utils srsran_phy)
|
||||
set_target_properties(srsran_rf_shared PROPERTIES VERSION ${SRSRAN_VERSION_STRING} SOVERSION ${SRSRAN_SOVERSION})
|
||||
|
||||
if (UHD_FOUND)
|
||||
target_link_libraries(srsran_rf ${UHD_LIBRARIES} ${Boost_LIBRARIES}) # Ubuntu 18.04 requires 'system' from Boost_LIBRARIES
|
||||
target_link_libraries(srsran_rf_shared ${UHD_LIBRARIES} ${Boost_LIBRARIES})
|
||||
endif (UHD_FOUND)
|
||||
|
||||
if (BLADERF_FOUND)
|
||||
target_link_libraries(srsran_rf ${BLADERF_LIBRARIES})
|
||||
target_link_libraries(srsran_rf_shared ${BLADERF_LIBRARIES})
|
||||
endif (BLADERF_FOUND)
|
||||
|
||||
if (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
target_link_libraries(srsran_rf ${SOAPYSDR_LIBRARIES})
|
||||
target_link_libraries(srsran_rf_shared ${SOAPYSDR_LIBRARIES})
|
||||
endif (SOAPYSDR_FOUND AND ENABLE_SOAPYSDR)
|
||||
|
||||
if(SKIQ_FOUND)
|
||||
target_link_libraries(srsran_rf ${SKIQ_LIBRARIES} rt)
|
||||
target_link_libraries(srsran_rf_shared ${SKIQ_LIBRARIES} rt)
|
||||
endif(SKIQ_FOUND)
|
||||
|
||||
if (ZEROMQ_FOUND)
|
||||
target_link_libraries(srsran_rf ${ZEROMQ_LIBRARIES})
|
||||
target_link_libraries(srsran_rf_shared ${ZEROMQ_LIBRARIES})
|
||||
add_executable(rf_zmq_test rf_zmq_test.c)
|
||||
target_link_libraries(rf_zmq_test srsran_rf)
|
||||
#add_test(rf_zmq_test rf_zmq_test)
|
||||
|
@ -115,6 +179,4 @@ if(RF_FOUND)
|
|||
add_executable(rf_file_test rf_file_test.c)
|
||||
target_link_libraries(rf_file_test srsran_rf)
|
||||
add_test(rf_file_test rf_file_test)
|
||||
|
||||
INSTALL(TARGETS srsran_rf DESTINATION ${LIBRARY_DIR})
|
||||
endif(RF_FOUND)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "rf_blade_imp.h"
|
||||
#include "rf_plugin.h"
|
||||
#include "srsran/phy/common/timestamp.h"
|
||||
#include "srsran/phy/utils/debug.h"
|
||||
#include "srsran/phy/utils/vector.h"
|
||||
|
@ -544,3 +545,44 @@ int rf_blade_send_timed(void* h,
|
|||
|
||||
return nsamples;
|
||||
}
|
||||
|
||||
rf_dev_t srsran_rf_dev_blade = {"bladeRF",
|
||||
rf_blade_devname,
|
||||
rf_blade_start_rx_stream,
|
||||
rf_blade_stop_rx_stream,
|
||||
rf_blade_flush_buffer,
|
||||
rf_blade_has_rssi,
|
||||
rf_blade_get_rssi,
|
||||
rf_blade_suppress_stdout,
|
||||
rf_blade_register_error_handler,
|
||||
rf_blade_open,
|
||||
.srsran_rf_open_multi = rf_blade_open_multi,
|
||||
rf_blade_close,
|
||||
rf_blade_set_rx_srate,
|
||||
rf_blade_set_rx_gain,
|
||||
rf_blade_set_rx_gain_ch,
|
||||
rf_blade_set_tx_gain,
|
||||
rf_blade_set_tx_gain_ch,
|
||||
rf_blade_get_rx_gain,
|
||||
rf_blade_get_tx_gain,
|
||||
rf_blade_get_info,
|
||||
rf_blade_set_rx_freq,
|
||||
rf_blade_set_tx_srate,
|
||||
rf_blade_set_tx_freq,
|
||||
rf_blade_get_time,
|
||||
NULL,
|
||||
rf_blade_recv_with_time,
|
||||
rf_blade_recv_with_time_multi,
|
||||
rf_blade_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_blade_send_timed_multi};
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
int register_plugin(rf_dev_t** rf_api)
|
||||
{
|
||||
if (rf_api == NULL) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
*rf_api = &srsran_rf_dev_blade;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
|
|
@ -19,11 +19,16 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_RF_BLADE_IMP_H_
|
||||
#define SRSRAN_RF_BLADE_IMP_H_
|
||||
|
||||
#include "srsran/config.h"
|
||||
#include "srsran/phy/rf/rf.h"
|
||||
|
||||
#define DEVNAME "bladerf"
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_blade;
|
||||
|
||||
SRSRAN_API int rf_blade_open(char* args, void** handler);
|
||||
|
||||
SRSRAN_API int rf_blade_open_multi(char* args, void** handler, uint32_t nof_channels);
|
||||
|
@ -99,3 +104,5 @@ SRSRAN_API int rf_blade_send_timed(void* h,
|
|||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
|
||||
#endif /* SRSRAN_RF_BLADE_IMP_H_ */
|
||||
|
|
|
@ -22,276 +22,58 @@
|
|||
#include "srsran/phy/rf/rf.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
/* RF frontend API */
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const char* (*srsran_rf_devname)(void* h);
|
||||
int (*srsran_rf_start_rx_stream)(void* h, bool now);
|
||||
int (*srsran_rf_stop_rx_stream)(void* h);
|
||||
void (*srsran_rf_flush_buffer)(void* h);
|
||||
bool (*srsran_rf_has_rssi)(void* h);
|
||||
float (*srsran_rf_get_rssi)(void* h);
|
||||
void (*srsran_rf_suppress_stdout)(void* h);
|
||||
void (*srsran_rf_register_error_handler)(void* h, srsran_rf_error_handler_t error_handler, void* arg);
|
||||
int (*srsran_rf_open)(char* args, void** h);
|
||||
int (*srsran_rf_open_multi)(char* args, void** h, uint32_t nof_channels);
|
||||
int (*srsran_rf_close)(void* h);
|
||||
double (*srsran_rf_set_rx_srate)(void* h, double freq);
|
||||
int (*srsran_rf_set_rx_gain)(void* h, double gain);
|
||||
int (*srsran_rf_set_rx_gain_ch)(void* h, uint32_t ch, double gain);
|
||||
int (*srsran_rf_set_tx_gain)(void* h, double gain);
|
||||
int (*srsran_rf_set_tx_gain_ch)(void* h, uint32_t ch, double gain);
|
||||
double (*srsran_rf_get_rx_gain)(void* h);
|
||||
double (*srsran_rf_get_tx_gain)(void* h);
|
||||
srsran_rf_info_t* (*srsran_rf_get_info)(void* h);
|
||||
double (*srsran_rf_set_rx_freq)(void* h, uint32_t ch, double freq);
|
||||
double (*srsran_rf_set_tx_srate)(void* h, double freq);
|
||||
double (*srsran_rf_set_tx_freq)(void* h, uint32_t ch, double freq);
|
||||
void (*srsran_rf_get_time)(void* h, time_t* secs, double* frac_secs);
|
||||
void (*srsran_rf_sync_pps)(void* h);
|
||||
int (*srsran_rf_recv_with_time)(void* h,
|
||||
void* data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t* secs,
|
||||
double* frac_secs);
|
||||
int (*srsran_rf_recv_with_time_multi)(void* h,
|
||||
void** data,
|
||||
uint32_t nsamples,
|
||||
bool blocking,
|
||||
time_t* secs,
|
||||
double* frac_secs);
|
||||
int (*srsran_rf_send_timed)(void* h,
|
||||
void* data,
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
int (*srsran_rf_send_timed_multi)(void* h,
|
||||
void** data,
|
||||
int nsamples,
|
||||
time_t secs,
|
||||
double frac_secs,
|
||||
bool has_time_spec,
|
||||
bool blocking,
|
||||
bool is_start_of_burst,
|
||||
bool is_end_of_burst);
|
||||
} rf_dev_t;
|
||||
|
||||
/* Define implementation for UHD */
|
||||
#ifdef ENABLE_UHD
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static srsran_rf_plugin_t plugin_uhd = {"libsrsran_rf_uhd.so", NULL, NULL};
|
||||
#else
|
||||
#include "rf_uhd_imp.h"
|
||||
|
||||
static rf_dev_t dev_uhd = {"UHD",
|
||||
rf_uhd_devname,
|
||||
rf_uhd_start_rx_stream,
|
||||
rf_uhd_stop_rx_stream,
|
||||
rf_uhd_flush_buffer,
|
||||
rf_uhd_has_rssi,
|
||||
rf_uhd_get_rssi,
|
||||
rf_uhd_suppress_stdout,
|
||||
rf_uhd_register_error_handler,
|
||||
rf_uhd_open,
|
||||
.srsran_rf_open_multi = rf_uhd_open_multi,
|
||||
rf_uhd_close,
|
||||
rf_uhd_set_rx_srate,
|
||||
rf_uhd_set_rx_gain,
|
||||
rf_uhd_set_rx_gain_ch,
|
||||
rf_uhd_set_tx_gain,
|
||||
rf_uhd_set_tx_gain_ch,
|
||||
rf_uhd_get_rx_gain,
|
||||
rf_uhd_get_tx_gain,
|
||||
rf_uhd_get_info,
|
||||
rf_uhd_set_rx_freq,
|
||||
rf_uhd_set_tx_srate,
|
||||
rf_uhd_set_tx_freq,
|
||||
rf_uhd_get_time,
|
||||
rf_uhd_sync_pps,
|
||||
rf_uhd_recv_with_time,
|
||||
rf_uhd_recv_with_time_multi,
|
||||
rf_uhd_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_uhd_send_timed_multi};
|
||||
static srsran_rf_plugin_t plugin_uhd = {"", NULL, &srsran_rf_dev_uhd};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define implementation for bladeRF */
|
||||
#ifdef ENABLE_BLADERF
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static srsran_rf_plugin_t plugin_blade = {"libsrsran_rf_blade.so", NULL, NULL};
|
||||
#else
|
||||
#include "rf_blade_imp.h"
|
||||
|
||||
static rf_dev_t dev_blade = {"bladeRF",
|
||||
rf_blade_devname,
|
||||
rf_blade_start_rx_stream,
|
||||
rf_blade_stop_rx_stream,
|
||||
rf_blade_flush_buffer,
|
||||
rf_blade_has_rssi,
|
||||
rf_blade_get_rssi,
|
||||
rf_blade_suppress_stdout,
|
||||
rf_blade_register_error_handler,
|
||||
rf_blade_open,
|
||||
.srsran_rf_open_multi = rf_blade_open_multi,
|
||||
rf_blade_close,
|
||||
rf_blade_set_rx_srate,
|
||||
rf_blade_set_rx_gain,
|
||||
rf_blade_set_rx_gain_ch,
|
||||
rf_blade_set_tx_gain,
|
||||
rf_blade_set_tx_gain_ch,
|
||||
rf_blade_get_rx_gain,
|
||||
rf_blade_get_tx_gain,
|
||||
rf_blade_get_info,
|
||||
rf_blade_set_rx_freq,
|
||||
rf_blade_set_tx_srate,
|
||||
rf_blade_set_tx_freq,
|
||||
rf_blade_get_time,
|
||||
NULL,
|
||||
rf_blade_recv_with_time,
|
||||
rf_blade_recv_with_time_multi,
|
||||
rf_blade_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_blade_send_timed_multi};
|
||||
static srsran_rf_plugin_t plugin_blade = {"", NULL, &srsran_rf_dev_blade};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define implementation for SoapySDR */
|
||||
#ifdef ENABLE_SOAPYSDR
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static srsran_rf_plugin_t plugin_soapy = {"libsrsran_rf_soapy.so", NULL, NULL};
|
||||
#else
|
||||
#include "rf_soapy_imp.h"
|
||||
|
||||
static rf_dev_t dev_soapy = {"soapy",
|
||||
rf_soapy_devname,
|
||||
rf_soapy_start_rx_stream,
|
||||
rf_soapy_stop_rx_stream,
|
||||
rf_soapy_flush_buffer,
|
||||
rf_soapy_has_rssi,
|
||||
rf_soapy_get_rssi,
|
||||
rf_soapy_suppress_stdout,
|
||||
rf_soapy_register_error_handler,
|
||||
rf_soapy_open,
|
||||
rf_soapy_open_multi,
|
||||
rf_soapy_close,
|
||||
rf_soapy_set_rx_srate,
|
||||
rf_soapy_set_rx_gain,
|
||||
rf_soapy_set_rx_gain_ch,
|
||||
rf_soapy_set_tx_gain,
|
||||
rf_soapy_set_tx_gain_ch,
|
||||
rf_soapy_get_rx_gain,
|
||||
rf_soapy_get_tx_gain,
|
||||
rf_soapy_get_info,
|
||||
rf_soapy_set_rx_freq,
|
||||
rf_soapy_set_tx_srate,
|
||||
rf_soapy_set_tx_freq,
|
||||
rf_soapy_get_time,
|
||||
NULL,
|
||||
rf_soapy_recv_with_time,
|
||||
rf_soapy_recv_with_time_multi,
|
||||
rf_soapy_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_soapy_send_timed_multi};
|
||||
|
||||
static srsran_rf_plugin_t plugin_soapy = {"", NULL, &srsran_rf_dev_soapy};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define implementation for UHD */
|
||||
/* Define implementation for ZeroMQ */
|
||||
#ifdef ENABLE_ZEROMQ
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static srsran_rf_plugin_t plugin_zmq = {"libsrsran_rf_zmq.so", NULL, NULL};
|
||||
#else
|
||||
#include "rf_zmq_imp.h"
|
||||
|
||||
static rf_dev_t dev_zmq = {"zmq",
|
||||
rf_zmq_devname,
|
||||
rf_zmq_start_rx_stream,
|
||||
rf_zmq_stop_rx_stream,
|
||||
rf_zmq_flush_buffer,
|
||||
rf_zmq_has_rssi,
|
||||
rf_zmq_get_rssi,
|
||||
rf_zmq_suppress_stdout,
|
||||
rf_zmq_register_error_handler,
|
||||
rf_zmq_open,
|
||||
.srsran_rf_open_multi = rf_zmq_open_multi,
|
||||
rf_zmq_close,
|
||||
rf_zmq_set_rx_srate,
|
||||
rf_zmq_set_rx_gain,
|
||||
rf_zmq_set_rx_gain_ch,
|
||||
rf_zmq_set_tx_gain,
|
||||
rf_zmq_set_tx_gain_ch,
|
||||
rf_zmq_get_rx_gain,
|
||||
rf_zmq_get_tx_gain,
|
||||
rf_zmq_get_info,
|
||||
rf_zmq_set_rx_freq,
|
||||
rf_zmq_set_tx_srate,
|
||||
rf_zmq_set_tx_freq,
|
||||
rf_zmq_get_time,
|
||||
NULL,
|
||||
rf_zmq_recv_with_time,
|
||||
rf_zmq_recv_with_time_multi,
|
||||
rf_zmq_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_zmq_send_timed_multi};
|
||||
static srsran_rf_plugin_t plugin_zmq = {"", NULL, &srsran_rf_dev_zmq};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define implementation for file-based RF */
|
||||
|
||||
#include "rf_file_imp.h"
|
||||
|
||||
static rf_dev_t dev_file = {"file",
|
||||
rf_file_devname,
|
||||
rf_file_start_rx_stream,
|
||||
rf_file_stop_rx_stream,
|
||||
rf_file_flush_buffer,
|
||||
rf_file_has_rssi,
|
||||
rf_file_get_rssi,
|
||||
rf_file_suppress_stdout,
|
||||
rf_file_register_error_handler,
|
||||
rf_file_open,
|
||||
.srsran_rf_open_multi = rf_file_open_multi,
|
||||
rf_file_close,
|
||||
rf_file_set_rx_srate,
|
||||
rf_file_set_rx_gain,
|
||||
rf_file_set_rx_gain_ch,
|
||||
rf_file_set_tx_gain,
|
||||
rf_file_set_tx_gain_ch,
|
||||
rf_file_get_rx_gain,
|
||||
rf_file_get_tx_gain,
|
||||
rf_file_get_info,
|
||||
rf_file_set_rx_freq,
|
||||
rf_file_set_tx_srate,
|
||||
rf_file_set_tx_freq,
|
||||
rf_file_get_time,
|
||||
NULL,
|
||||
rf_file_recv_with_time,
|
||||
rf_file_recv_with_time_multi,
|
||||
rf_file_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_file_send_timed_multi};
|
||||
static srsran_rf_plugin_t plugin_file = {"", NULL, &srsran_rf_dev_file};
|
||||
|
||||
/* Define implementation for Sidekiq */
|
||||
#ifdef ENABLE_SIDEKIQ
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static srsran_rf_plugin_t plugin_skiq = {"libsrsran_rf_skiq.so", NULL, NULL};
|
||||
#else
|
||||
#include "rf_skiq_imp.h"
|
||||
|
||||
static rf_dev_t dev_skiq = {.name = "Sidekiq",
|
||||
.srsran_rf_devname = rf_skiq_devname,
|
||||
.srsran_rf_start_rx_stream = rf_skiq_start_rx_stream,
|
||||
.srsran_rf_stop_rx_stream = rf_skiq_stop_rx_stream,
|
||||
.srsran_rf_flush_buffer = rf_skiq_flush_buffer,
|
||||
.srsran_rf_has_rssi = rf_skiq_has_rssi,
|
||||
.srsran_rf_get_rssi = rf_skiq_get_rssi,
|
||||
.srsran_rf_suppress_stdout = rf_skiq_suppress_stdout,
|
||||
.srsran_rf_register_error_handler = rf_skiq_register_error_handler,
|
||||
.srsran_rf_open = rf_skiq_open,
|
||||
.srsran_rf_open_multi = rf_skiq_open_multi,
|
||||
.srsran_rf_close = rf_skiq_close,
|
||||
.srsran_rf_set_rx_srate = rf_skiq_set_rx_srate,
|
||||
.srsran_rf_set_tx_srate = rf_skiq_set_tx_srate,
|
||||
.srsran_rf_set_rx_gain = rf_skiq_set_rx_gain,
|
||||
.srsran_rf_set_tx_gain = rf_skiq_set_tx_gain,
|
||||
.srsran_rf_set_tx_gain_ch = rf_skiq_set_tx_gain_ch,
|
||||
.srsran_rf_set_rx_gain_ch = rf_skiq_set_rx_gain_ch,
|
||||
.srsran_rf_get_rx_gain = rf_skiq_get_rx_gain,
|
||||
.srsran_rf_get_tx_gain = rf_skiq_get_tx_gain,
|
||||
.srsran_rf_get_info = rf_skiq_get_info,
|
||||
.srsran_rf_set_rx_freq = rf_skiq_set_rx_freq,
|
||||
.srsran_rf_set_tx_freq = rf_skiq_set_tx_freq,
|
||||
.srsran_rf_get_time = rf_skiq_get_time,
|
||||
.srsran_rf_recv_with_time = rf_skiq_recv_with_time,
|
||||
.srsran_rf_recv_with_time_multi = rf_skiq_recv_with_time_multi,
|
||||
.srsran_rf_send_timed = rf_skiq_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_skiq_send_timed_multi};
|
||||
static srsran_rf_plugin_t plugin_skiq = {"", NULL, &srsran_rf_dev_skiq};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#define ENABLE_DUMMY_DEV
|
||||
|
@ -304,34 +86,36 @@ int dummy_rcv()
|
|||
}
|
||||
void dummy_fnc() {}
|
||||
|
||||
static rf_dev_t dev_dummy = {"dummy", dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc,
|
||||
dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc,
|
||||
dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_rcv,
|
||||
dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc};
|
||||
static rf_dev_t srsran_rf_dev_dummy = {
|
||||
"dummy", dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc,
|
||||
dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc,
|
||||
dummy_fnc, dummy_fnc, dummy_fnc, dummy_rcv, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc};
|
||||
static srsran_rf_plugin_t plugin_dummy = {"", NULL, &srsran_rf_dev_dummy};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Collection of all currently supported RF devices
|
||||
* Collection of all currently available RF plugins
|
||||
*/
|
||||
static rf_dev_t* available_devices[] = {
|
||||
static srsran_rf_plugin_t* rf_plugins[] = {
|
||||
|
||||
#ifdef ENABLE_UHD
|
||||
&dev_uhd,
|
||||
&plugin_uhd,
|
||||
#endif
|
||||
#ifdef ENABLE_SOAPYSDR
|
||||
&dev_soapy,
|
||||
&plugin_soapy,
|
||||
#endif
|
||||
#ifdef ENABLE_BLADERF
|
||||
&dev_blade,
|
||||
&plugin_blade,
|
||||
#endif
|
||||
#ifdef ENABLE_ZEROMQ
|
||||
&dev_zmq,
|
||||
&plugin_zmq,
|
||||
#endif
|
||||
#ifdef ENABLE_SIDEKIQ
|
||||
&dev_skiq,
|
||||
&plugin_skiq,
|
||||
#endif
|
||||
#ifdef ENABLE_DUMMY_DEV
|
||||
&dev_dummy,
|
||||
&plugin_dummy,
|
||||
#endif
|
||||
&dev_file,
|
||||
&plugin_file,
|
||||
NULL};
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_RF_IMP_TRX_H
|
||||
#define SRSRAN_RF_IMP_TRX_H
|
||||
|
||||
#include "rf_file_imp.h"
|
||||
#include "rf_file_imp_trx.h"
|
||||
#include "rf_helper.h"
|
||||
|
@ -865,4 +862,32 @@ clean_exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
rf_dev_t srsran_rf_dev_file = {"file",
|
||||
rf_file_devname,
|
||||
rf_file_start_rx_stream,
|
||||
rf_file_stop_rx_stream,
|
||||
rf_file_flush_buffer,
|
||||
rf_file_has_rssi,
|
||||
rf_file_get_rssi,
|
||||
rf_file_suppress_stdout,
|
||||
rf_file_register_error_handler,
|
||||
rf_file_open,
|
||||
.srsran_rf_open_multi = rf_file_open_multi,
|
||||
rf_file_close,
|
||||
rf_file_set_rx_srate,
|
||||
rf_file_set_rx_gain,
|
||||
rf_file_set_rx_gain_ch,
|
||||
rf_file_set_tx_gain,
|
||||
rf_file_set_tx_gain_ch,
|
||||
rf_file_get_rx_gain,
|
||||
rf_file_get_tx_gain,
|
||||
rf_file_get_info,
|
||||
rf_file_set_rx_freq,
|
||||
rf_file_set_tx_srate,
|
||||
rf_file_set_tx_freq,
|
||||
rf_file_get_time,
|
||||
NULL,
|
||||
rf_file_recv_with_time,
|
||||
rf_file_recv_with_time_multi,
|
||||
rf_file_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_file_send_timed_multi};
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#define PARAM_LEN (128)
|
||||
#define PARAM_LEN_SHORT (PARAM_LEN / 2)
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_file;
|
||||
|
||||
SRSRAN_API const char* rf_file_devname(void* h);
|
||||
|
||||
SRSRAN_API int rf_file_start_rx_stream(void* h, bool now);
|
||||
|
@ -136,6 +138,7 @@ SRSRAN_API int rf_file_send_timed_multi(void* h,
|
|||
* @param[in] base_srate Sample rate of RX and TX files
|
||||
* @return SRSRAN_SUCCESS on success, otherwise error code
|
||||
*/
|
||||
SRSRAN_API int rf_file_open_file(void** h, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate);
|
||||
SRSRAN_API int
|
||||
rf_file_open_file(void** h, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate);
|
||||
|
||||
#endif // SRSRAN_RF_FILE_IMP_H
|
||||
|
|
|
@ -19,17 +19,19 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "rf_dev.h"
|
||||
#include "srsran/phy/rf/rf.h"
|
||||
#include "srsran/phy/utils/debug.h"
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
|
||||
int rf_get_available_devices(char** devnames, int max_strlen)
|
||||
{
|
||||
int i = 0;
|
||||
while (available_devices[i]->name) {
|
||||
strncpy(devnames[i], available_devices[i]->name, max_strlen);
|
||||
while (rf_plugins[i] != NULL) {
|
||||
if (rf_plugins[i]->rf_api != NULL) {
|
||||
strncpy(devnames[i], rf_plugins[i]->rf_api->name, max_strlen);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
|
@ -104,20 +106,22 @@ int srsran_rf_open_devname(srsran_rf_t* rf, const char* devname, char* args, uin
|
|||
rf->thread_gain_run = false;
|
||||
|
||||
bool no_rf_devs_detected = true;
|
||||
printf("Available RF device list:");
|
||||
for (unsigned int i = 0; available_devices[i]; i++) {
|
||||
printf("Supported RF device list:");
|
||||
for (unsigned int i = 0; rf_plugins[i] && rf_plugins[i]->rf_api; i++) {
|
||||
no_rf_devs_detected = false;
|
||||
printf(" %s ", available_devices[i]->name);
|
||||
printf(" %s", rf_plugins[i]->rf_api->name);
|
||||
}
|
||||
printf("%s\n", no_rf_devs_detected ? " <none>" : "");
|
||||
|
||||
// Try to open the device if name is provided
|
||||
if (devname && devname[0] != '\0') {
|
||||
int i = 0;
|
||||
while (available_devices[i] != NULL) {
|
||||
if (!strcasecmp(available_devices[i]->name, devname)) {
|
||||
rf->dev = available_devices[i];
|
||||
return available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels);
|
||||
while (rf_plugins[i] != NULL) {
|
||||
if (rf_plugins[i]->rf_api) {
|
||||
if (!strcasecmp(rf_plugins[i]->rf_api->name, devname)) {
|
||||
rf->dev = rf_plugins[i]->rf_api;
|
||||
return rf_plugins[i]->rf_api->srsran_rf_open_multi(args, &rf->handler, nof_channels);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -129,16 +133,16 @@ int srsran_rf_open_devname(srsran_rf_t* rf, const char* devname, char* args, uin
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// auto-mode, try to open in order of apperance in available_devices[] array
|
||||
// auto-mode, try to open in order of apperance in rf_plugins[] array
|
||||
int i = 0;
|
||||
while (available_devices[i] != NULL) {
|
||||
printf("Trying to open RF device '%s'\n", available_devices[i]->name);
|
||||
if (!available_devices[i]->srsran_rf_open_multi(args, &rf->handler, nof_channels)) {
|
||||
rf->dev = available_devices[i];
|
||||
printf("RF device '%s' successfully opened\n", available_devices[i]->name);
|
||||
while (rf_plugins[i] != NULL && rf_plugins[i]->rf_api != NULL) {
|
||||
printf("Trying to open RF device '%s'\n", rf_plugins[i]->rf_api->name);
|
||||
if (!rf_plugins[i]->rf_api->srsran_rf_open_multi(args, &rf->handler, nof_channels)) {
|
||||
rf->dev = rf_plugins[i]->rf_api;
|
||||
printf("RF device '%s' successfully opened\n", rf_plugins[i]->rf_api->name);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
printf("Unable to open RF device '%s'\n", available_devices[i]->name);
|
||||
printf("Unable to open RF device '%s'\n", rf_plugins[i]->rf_api->name);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -150,7 +154,7 @@ int srsran_rf_open_devname(srsran_rf_t* rf, const char* devname, char* args, uin
|
|||
|
||||
int srsran_rf_open_file(srsran_rf_t* rf, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate)
|
||||
{
|
||||
rf->dev = &dev_file;
|
||||
rf->dev = &srsran_rf_dev_file;
|
||||
|
||||
// file abstraction has custom "open" function with file-related args
|
||||
return rf_file_open_file(&rf->handler, rx_files, tx_files, nof_channels, base_srate);
|
||||
|
@ -400,3 +404,93 @@ int srsran_rf_send_timed2(srsran_rf_t* rf,
|
|||
{
|
||||
return srsran_rf_send_timed3(rf, data, nsamples, secs, frac_secs, true, true, is_start_of_burst, is_end_of_burst);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
static void unload_plugin(srsran_rf_plugin_t* rf_plugin)
|
||||
{
|
||||
if (rf_plugin == NULL) {
|
||||
return;
|
||||
}
|
||||
if (rf_plugin->dl_handle != NULL) {
|
||||
rf_plugin->rf_api = NULL;
|
||||
dlclose(rf_plugin->dl_handle);
|
||||
rf_plugin->dl_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int load_plugin(srsran_rf_plugin_t* rf_plugin)
|
||||
{
|
||||
if (rf_plugin->rf_api != NULL) {
|
||||
// already loaded
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
rf_plugin->dl_handle = dlopen(rf_plugin->plugin_name, RTLD_NOW);
|
||||
if (rf_plugin->dl_handle == NULL) {
|
||||
// Not an error, if loading failed due to missing dependencies.
|
||||
// Mark this plugin as not available and return SUCCESS.
|
||||
INFO("Failed to load RF plugin %s: %s", rf_plugin->plugin_name, dlerror());
|
||||
rf_plugin->rf_api = NULL;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// clear errors
|
||||
dlerror();
|
||||
char* err = NULL;
|
||||
|
||||
// load symbols
|
||||
int (*register_plugin)(rf_dev_t * *rf_api) = dlsym(rf_plugin->dl_handle, "register_plugin");
|
||||
if ((err = dlerror()) != NULL) {
|
||||
ERROR("Error loading symbol '%s': %s", "register_plugin", err);
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// register plugin
|
||||
int ret = register_plugin(&rf_plugin->rf_api);
|
||||
if (ret != SRSRAN_SUCCESS) {
|
||||
ERROR("Failed to register RF API for plugin %s", rf_plugin->plugin_name);
|
||||
goto clean_exit;
|
||||
}
|
||||
return SRSRAN_SUCCESS;
|
||||
clean_exit:
|
||||
unload_plugin(rf_plugin);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
||||
int srsran_rf_load_plugins()
|
||||
{
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
for (unsigned int i = 0; rf_plugins[i]; i++) {
|
||||
if (load_plugin(rf_plugins[i]) != SRSRAN_SUCCESS) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Active RF plugins:");
|
||||
for (unsigned int i = 0; rf_plugins[i]; i++) {
|
||||
if (rf_plugins[i]->dl_handle != NULL) {
|
||||
printf(" %s", rf_plugins[i]->plugin_name);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Inactive RF plugins:");
|
||||
for (unsigned int i = 0; rf_plugins[i]; i++) {
|
||||
if (rf_plugins[i]->dl_handle == NULL) {
|
||||
printf(" %s", rf_plugins[i]->plugin_name);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Search and load plugins when this library is loaded (shared) or right before main (static)
|
||||
void __attribute__((constructor)) init()
|
||||
{
|
||||
if (srsran_rf_load_plugins() != SRSRAN_SUCCESS) {
|
||||
ERROR("Failed to load RF plugins");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2022 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_RF_PLUGIN_H
|
||||
#define SRSRAN_RF_PLUGIN_H
|
||||
|
||||
#include "srsran/phy/rf/rf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SRSRAN_API int register_plugin(rf_dev_t** rf_api);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SRSRAN_RF_PLUGIN_H */
|
|
@ -24,6 +24,7 @@
|
|||
#include <sidekiq_api.h>
|
||||
|
||||
#include "rf_helper.h"
|
||||
#include "rf_plugin.h"
|
||||
#include "rf_skiq_imp.h"
|
||||
#include "rf_skiq_imp_card.h"
|
||||
|
||||
|
@ -948,3 +949,43 @@ int rf_skiq_send_timed_multi(void* h_,
|
|||
|
||||
return (int)rpm;
|
||||
}
|
||||
|
||||
rf_dev_t srsran_rf_dev_skiq = {.name = "Sidekiq",
|
||||
.srsran_rf_devname = rf_skiq_devname,
|
||||
.srsran_rf_start_rx_stream = rf_skiq_start_rx_stream,
|
||||
.srsran_rf_stop_rx_stream = rf_skiq_stop_rx_stream,
|
||||
.srsran_rf_flush_buffer = rf_skiq_flush_buffer,
|
||||
.srsran_rf_has_rssi = rf_skiq_has_rssi,
|
||||
.srsran_rf_get_rssi = rf_skiq_get_rssi,
|
||||
.srsran_rf_suppress_stdout = rf_skiq_suppress_stdout,
|
||||
.srsran_rf_register_error_handler = rf_skiq_register_error_handler,
|
||||
.srsran_rf_open = rf_skiq_open,
|
||||
.srsran_rf_open_multi = rf_skiq_open_multi,
|
||||
.srsran_rf_close = rf_skiq_close,
|
||||
.srsran_rf_set_rx_srate = rf_skiq_set_rx_srate,
|
||||
.srsran_rf_set_tx_srate = rf_skiq_set_tx_srate,
|
||||
.srsran_rf_set_rx_gain = rf_skiq_set_rx_gain,
|
||||
.srsran_rf_set_tx_gain = rf_skiq_set_tx_gain,
|
||||
.srsran_rf_set_tx_gain_ch = rf_skiq_set_tx_gain_ch,
|
||||
.srsran_rf_set_rx_gain_ch = rf_skiq_set_rx_gain_ch,
|
||||
.srsran_rf_get_rx_gain = rf_skiq_get_rx_gain,
|
||||
.srsran_rf_get_tx_gain = rf_skiq_get_tx_gain,
|
||||
.srsran_rf_get_info = rf_skiq_get_info,
|
||||
.srsran_rf_set_rx_freq = rf_skiq_set_rx_freq,
|
||||
.srsran_rf_set_tx_freq = rf_skiq_set_tx_freq,
|
||||
.srsran_rf_get_time = rf_skiq_get_time,
|
||||
.srsran_rf_recv_with_time = rf_skiq_recv_with_time,
|
||||
.srsran_rf_recv_with_time_multi = rf_skiq_recv_with_time_multi,
|
||||
.srsran_rf_send_timed = rf_skiq_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_skiq_send_timed_multi};
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
int register_plugin(rf_dev_t** rf_api)
|
||||
{
|
||||
if (rf_api == NULL) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
*rf_api = &srsran_rf_dev_skiq;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "srsran/config.h"
|
||||
#include "srsran/phy/rf/rf.h"
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_skiq;
|
||||
|
||||
SRSRAN_API int rf_skiq_open(char* args, void** handler);
|
||||
|
||||
SRSRAN_API int rf_skiq_open_multi(char* args, void** handler, uint32_t nof_rx_antennas);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "rf_helper.h"
|
||||
#include "rf_plugin.h"
|
||||
#include "rf_soapy_imp.h"
|
||||
#include "srsran/phy/common/phy_common.h"
|
||||
#include "srsran/phy/utils/debug.h"
|
||||
|
@ -34,8 +35,8 @@
|
|||
#include <SoapySDR/Formats.h>
|
||||
#include <SoapySDR/Logger.h>
|
||||
#include <SoapySDR/Time.h>
|
||||
#include <SoapySDR/Version.h>
|
||||
#include <SoapySDR/Types.h>
|
||||
#include <SoapySDR/Version.h>
|
||||
|
||||
#define HAVE_ASYNC_THREAD 0
|
||||
|
||||
|
@ -862,7 +863,7 @@ int rf_soapy_recv_with_time_multi(void* h,
|
|||
int rf_soapy_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs)
|
||||
{
|
||||
void* data_multi[SRSRAN_MAX_PORTS] = {NULL};
|
||||
data_multi[0] = data;
|
||||
data_multi[0] = data;
|
||||
return rf_soapy_recv_with_time_multi(h, data_multi, nsamples, blocking, secs, frac_secs);
|
||||
}
|
||||
|
||||
|
@ -1003,3 +1004,44 @@ int rf_soapy_send_timed_multi(void* h,
|
|||
|
||||
return n;
|
||||
}
|
||||
|
||||
rf_dev_t srsran_rf_dev_soapy = {"soapy",
|
||||
rf_soapy_devname,
|
||||
rf_soapy_start_rx_stream,
|
||||
rf_soapy_stop_rx_stream,
|
||||
rf_soapy_flush_buffer,
|
||||
rf_soapy_has_rssi,
|
||||
rf_soapy_get_rssi,
|
||||
rf_soapy_suppress_stdout,
|
||||
rf_soapy_register_error_handler,
|
||||
rf_soapy_open,
|
||||
rf_soapy_open_multi,
|
||||
rf_soapy_close,
|
||||
rf_soapy_set_rx_srate,
|
||||
rf_soapy_set_rx_gain,
|
||||
rf_soapy_set_rx_gain_ch,
|
||||
rf_soapy_set_tx_gain,
|
||||
rf_soapy_set_tx_gain_ch,
|
||||
rf_soapy_get_rx_gain,
|
||||
rf_soapy_get_tx_gain,
|
||||
rf_soapy_get_info,
|
||||
rf_soapy_set_rx_freq,
|
||||
rf_soapy_set_tx_srate,
|
||||
rf_soapy_set_tx_freq,
|
||||
rf_soapy_get_time,
|
||||
NULL,
|
||||
rf_soapy_recv_with_time,
|
||||
rf_soapy_recv_with_time_multi,
|
||||
rf_soapy_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_soapy_send_timed_multi};
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
int register_plugin(rf_dev_t** rf_api)
|
||||
{
|
||||
if (rf_api == NULL) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
*rf_api = &srsran_rf_dev_soapy;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <stdint.h>
|
||||
#define DEVNAME_SOAPY "soapy"
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_soapy;
|
||||
|
||||
SRSRAN_API int rf_soapy_open(char* args, void** handler);
|
||||
|
||||
SRSRAN_API int rf_soapy_open_multi(char* args, void** handler, uint32_t num_requested_channels);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <uhd/usrp/multi_usrp.hpp>
|
||||
|
||||
#include "rf_helper.h"
|
||||
#include "rf_plugin.h"
|
||||
#include "srsran/phy/utils/debug.h"
|
||||
#include "srsran/phy/utils/vector.h"
|
||||
|
||||
|
@ -1544,3 +1545,44 @@ int rf_uhd_send_timed_multi(void* h,
|
|||
|
||||
return nsamples;
|
||||
}
|
||||
|
||||
rf_dev_t srsran_rf_dev_uhd = {"UHD",
|
||||
rf_uhd_devname,
|
||||
rf_uhd_start_rx_stream,
|
||||
rf_uhd_stop_rx_stream,
|
||||
rf_uhd_flush_buffer,
|
||||
rf_uhd_has_rssi,
|
||||
rf_uhd_get_rssi,
|
||||
rf_uhd_suppress_stdout,
|
||||
rf_uhd_register_error_handler,
|
||||
rf_uhd_open,
|
||||
rf_uhd_open_multi,
|
||||
rf_uhd_close,
|
||||
rf_uhd_set_rx_srate,
|
||||
rf_uhd_set_rx_gain,
|
||||
rf_uhd_set_rx_gain_ch,
|
||||
rf_uhd_set_tx_gain,
|
||||
rf_uhd_set_tx_gain_ch,
|
||||
rf_uhd_get_rx_gain,
|
||||
rf_uhd_get_tx_gain,
|
||||
rf_uhd_get_info,
|
||||
rf_uhd_set_rx_freq,
|
||||
rf_uhd_set_tx_srate,
|
||||
rf_uhd_set_tx_freq,
|
||||
rf_uhd_get_time,
|
||||
rf_uhd_sync_pps,
|
||||
rf_uhd_recv_with_time,
|
||||
rf_uhd_recv_with_time_multi,
|
||||
rf_uhd_send_timed,
|
||||
rf_uhd_send_timed_multi};
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
int register_plugin(rf_dev_t** rf_api)
|
||||
{
|
||||
if (rf_api == NULL) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
*rf_api = &srsran_rf_dev_uhd;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
|
|
@ -38,6 +38,8 @@ extern "C" {
|
|||
#define DEVNAME_E3X0 "uhd_e3x0"
|
||||
#define DEVNAME_UNKNOWN "uhd_unknown"
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_uhd;
|
||||
|
||||
SRSRAN_API int rf_uhd_open(char* args, void** handler);
|
||||
|
||||
SRSRAN_API int rf_uhd_open_multi(char* args, void** handler, uint32_t nof_channels);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "rf_zmq_imp.h"
|
||||
#include "rf_helper.h"
|
||||
#include "rf_plugin.h"
|
||||
#include "rf_zmq_imp_trx.h"
|
||||
#include <math.h>
|
||||
#include <srsran/phy/common/phy_common.h>
|
||||
|
@ -970,7 +971,7 @@ int rf_zmq_send_timed_multi(void* h,
|
|||
}
|
||||
|
||||
// Scale according to current gain
|
||||
srsran_vec_sc_prod_cfc(buf, tx_gain, buf, nsamples_baseband);
|
||||
srsran_vec_sc_prod_cfc(buf, tx_gain, buf, nsamples_baseband);
|
||||
|
||||
// Finally, transmit baseband
|
||||
int n = rf_zmq_tx_baseband(&handler->transmitter[i], buf, nsamples_baseband);
|
||||
|
@ -992,3 +993,44 @@ clean_exit:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rf_dev_t srsran_rf_dev_zmq = {"zmq",
|
||||
rf_zmq_devname,
|
||||
rf_zmq_start_rx_stream,
|
||||
rf_zmq_stop_rx_stream,
|
||||
rf_zmq_flush_buffer,
|
||||
rf_zmq_has_rssi,
|
||||
rf_zmq_get_rssi,
|
||||
rf_zmq_suppress_stdout,
|
||||
rf_zmq_register_error_handler,
|
||||
rf_zmq_open,
|
||||
.srsran_rf_open_multi = rf_zmq_open_multi,
|
||||
rf_zmq_close,
|
||||
rf_zmq_set_rx_srate,
|
||||
rf_zmq_set_rx_gain,
|
||||
rf_zmq_set_rx_gain_ch,
|
||||
rf_zmq_set_tx_gain,
|
||||
rf_zmq_set_tx_gain_ch,
|
||||
rf_zmq_get_rx_gain,
|
||||
rf_zmq_get_tx_gain,
|
||||
rf_zmq_get_info,
|
||||
rf_zmq_set_rx_freq,
|
||||
rf_zmq_set_tx_srate,
|
||||
rf_zmq_set_tx_freq,
|
||||
rf_zmq_get_time,
|
||||
NULL,
|
||||
rf_zmq_recv_with_time,
|
||||
rf_zmq_recv_with_time_multi,
|
||||
rf_zmq_send_timed,
|
||||
.srsran_rf_send_timed_multi = rf_zmq_send_timed_multi};
|
||||
|
||||
#ifdef ENABLE_RF_PLUGINS
|
||||
int register_plugin(rf_dev_t** rf_api)
|
||||
{
|
||||
if (rf_api == NULL) {
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
*rf_api = &srsran_rf_dev_zmq;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
#endif /* ENABLE_RF_PLUGINS */
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#define DEVNAME_ZMQ "ZeroMQ"
|
||||
|
||||
extern rf_dev_t srsran_rf_dev_zmq;
|
||||
|
||||
SRSRAN_API int rf_zmq_open(char* args, void** handler);
|
||||
|
||||
SRSRAN_API int rf_zmq_open_multi(char* args, void** handler, uint32_t nof_channels);
|
||||
|
|
|
@ -102,12 +102,11 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|||
// send data subframe per subframe
|
||||
uint32_t num_txed_samples = 0;
|
||||
|
||||
|
||||
// initial transmission without ts
|
||||
void* data_ptr[SRSRAN_MAX_PORTS] = {NULL};
|
||||
cf_t tx_buffer[NOF_RX_ANT][SF_LEN];
|
||||
cf_t tx_buffer[NOF_RX_ANT][SF_LEN];
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof(cf_t));
|
||||
data_ptr[c] = &tx_buffer[c][0];
|
||||
}
|
||||
int ret = srsran_rf_send_multi(&enb_radio, (void**)data_ptr, SF_LEN, true, true, false);
|
||||
|
@ -125,7 +124,7 @@ void enb_tx_function(const char* tx_args, bool timed_tx)
|
|||
|
||||
// prepare data buffer
|
||||
for (int c = 0; c < NOF_RX_ANT; c++) {
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof (cf_t));
|
||||
memcpy(&tx_buffer[c], &enb_tx_buffer[c][num_txed_samples], SF_LEN * sizeof(cf_t));
|
||||
data_ptr[c] = &tx_buffer[c][0];
|
||||
}
|
||||
|
||||
|
@ -243,34 +242,34 @@ int param_test(const char* args_param, const int num_channels)
|
|||
|
||||
int main()
|
||||
{
|
||||
// // two Rx ports
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
// // two Rx ports
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port1=ipc://dl1", 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// // multiple rx ports, no channel index provided
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
// // multiple rx ports, no channel index provided
|
||||
// if (param_test("rx_port=ipc://dl0,rx_port=ipc://dl1,rx_port=ipc://dl2,rx_port=ipc://dl3,base_srate=1.92e6", 4)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// // One Rx, one Tx and all generic options
|
||||
// if (param_test("rx_port0=tcp://"
|
||||
// "localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
||||
// 1)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
// // One Rx, one Tx and all generic options
|
||||
// if (param_test("rx_port0=tcp://"
|
||||
// "localhost:2000,rx_format=sc16,tx_format=sc16,tx_type=pub,rx_type=sub,base_srate=1.92e6,id=test",
|
||||
// 1)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
// // 1 port, 2 antennas, MIMO freq config
|
||||
// if (param_test(
|
||||
// "tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
||||
// "localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
||||
// 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
// // 1 port, 2 antennas, MIMO freq config
|
||||
// if (param_test(
|
||||
// "tx_port0=tcp://*:2001,tx_port1=tcp://*:2003,rx_port0=tcp://localhost:2000,rx_port1=tcp://"
|
||||
// "localhost:2002,id=ue,base_srate=23.04e6,tx_freq0=2510e6,tx_freq1=2510e6,rx_freq0=2630e6,,rx_freq1=2630e6",
|
||||
// 2)) {
|
||||
// fprintf(stderr, "Param test failed!\n");
|
||||
// return SRSRAN_ERROR;
|
||||
// }
|
||||
|
||||
#if NOF_RX_ANT == 1
|
||||
// single tx, single rx with continuous transmissions (no timed tx) using IPC transport
|
||||
|
|
|
@ -95,13 +95,13 @@ add_executable(psss_file_test psss_file_test.c)
|
|||
target_link_libraries(psss_file_test srsran_phy)
|
||||
|
||||
# SL TM 2
|
||||
add_test(sync_sl_test_tm2_p6_c_0 sync_sl_test -p 6 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat)
|
||||
add_test(sync_sl_test_tm2_p15_c_84 sync_sl_test -p 15 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat)
|
||||
add_test(sync_sl_test_tm2_p25_c_168 sync_sl_test -p 25 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
add_test(sync_sl_test_tm2_p50_c_252 sync_sl_test -p 50 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat)
|
||||
add_test(sync_sl_test_tm2_p100_c_335 sync_sl_test -p 100 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
add_test(sync_sl_test_tm2_p6_c_0 sync_sl_test -p 6 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p6_c0_s1.92e6.dat)
|
||||
add_test(sync_sl_test_tm2_p15_c_84 sync_sl_test -p 15 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p15_c84_s3.84e6.dat)
|
||||
add_test(sync_sl_test_tm2_p25_c_168 sync_sl_test -p 25 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
add_test(sync_sl_test_tm2_p50_c_252 sync_sl_test -p 50 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p50_c252_s15.36e6.dat)
|
||||
add_test(sync_sl_test_tm2_p100_c_335 sync_sl_test -p 100 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p100_c335_s30.72e6.dat)
|
||||
# Sample offset
|
||||
add_test(sync_sl_test_tm2_p25_c_168_so sync_sl_test -p 25 -d -o 300 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
add_test(sync_sl_test_tm2_p25_c_168_so sync_sl_test -p 25 -d -o 300 -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm2_p25_c168_s7.68e6.dat)
|
||||
# Self-test
|
||||
add_test(sync_sl_test_tm2_self_test_p25_c_168 sync_sl_test -p 25 -c 168 -d)
|
||||
# Self-test with frequency offset
|
||||
|
@ -110,13 +110,13 @@ add_test(sync_sl_test_tm2_self_test_p25_c_168_fo sync_sl_test -p 25 -c 168 -d -f
|
|||
add_test(sync_sl_test_tm2_self_test_p25_c_168_fo_so sync_sl_test -p 25 -c 168 -d -f 100 -o 3600)
|
||||
|
||||
# SL TM 4
|
||||
add_test(sync_sl_test_tm4_p6_c_0 sync_sl_test -p 6 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p6_c0_size6_num1_cshift0_s1.92e6.dat)
|
||||
add_test(sync_sl_test_tm4_p15_c_84 sync_sl_test -p 15 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p15_c84_size5_num3_cshift0_s3.84e6.dat)
|
||||
add_test(sync_sl_test_tm4_p25_c_168 sync_sl_test -p 25 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat)
|
||||
add_test(sync_sl_test_tm4_p50_c_252 sync_sl_test -p 50 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p50_c252_size10_num5_cshift0_s15.36e6.dat)
|
||||
#add_test(sync_sl_test_tm4_p100_c_335 sync_sl_test -p 100 -t 4 -d -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat)
|
||||
add_test(sync_sl_test_tm4_p6_c_0 sync_sl_test -p 6 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p6_c0_size6_num1_cshift0_s1.92e6.dat)
|
||||
add_test(sync_sl_test_tm4_p15_c_84 sync_sl_test -p 15 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p15_c84_size5_num3_cshift0_s3.84e6.dat)
|
||||
add_test(sync_sl_test_tm4_p25_c_168 sync_sl_test -p 25 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat)
|
||||
add_test(sync_sl_test_tm4_p50_c_252 sync_sl_test -p 50 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p50_c252_size10_num5_cshift0_s15.36e6.dat)
|
||||
#add_test(sync_sl_test_tm4_p100_c_335 sync_sl_test -p 100 -t 4 -d -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p100_c335_size10_num10_cshift0_s30.72e6.dat)
|
||||
# Sample offset
|
||||
add_test(sync_sl_test_tm4_p25_c_168_so sync_sl_test -p 25 -t 4 -d -o 300 -i ${CMAKE_HOME_DIRECTORY}/lib/src/phy/phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat )
|
||||
add_test(sync_sl_test_tm4_p25_c_168_so sync_sl_test -p 25 -t 4 -d -o 300 -i ${CMAKE_CURRENT_SOURCE_DIR}/../../phch/test/signal_sidelink_ideal_tm4_p25_c168_size5_num5_cshift0_s7.68e6.dat )
|
||||
# Self-test
|
||||
add_test(sync_sl_test_self_test_tm4_p25_c_168 sync_sl_test -p 25 -t 4 -c 168 -d)
|
||||
# Self-test with frequency offset
|
||||
|
@ -185,4 +185,4 @@ target_link_libraries(ssb_file_test srsran_phy)
|
|||
# Captured with command: lib/examples/usrp_capture -a type=x300,clock=external,sampling_rate=46.08e6,rx_subdev_spec=B:0 -g 20 -r 46.08e6 -n 460800 -f 3502.8e6 -o /tmp/n78.fo35028.fs2304M.data
|
||||
add_nr_test(ssb_file_test_tdd ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/n78.fo35028.fs4608M.data -v -r 46.08e6 -f 3502.8e6 -F 3512.64e6 -n 460800 -A 500 357802 2 0 1 0)
|
||||
# Capture with third-party gNB on band n3 (FDD) 15kHz SSB SCS, f_s=15.36e6, f_c=1842.5e6, f_c_ssb=1842.05e6, PCI=500
|
||||
add_nr_test(ssb_file_test_fdd ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../../ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -v -r 15.36e6 -f 1842.5e6 -F 1842.05e6 -n 15360 -d fdd -s 15 -A 500 2200 0 0 0 0)
|
||||
add_nr_test(ssb_file_test_fdd ssb_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/../../ue/test/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -v -r 15.36e6 -f 1842.5e6 -F 1842.05e6 -n 15360 -d fdd -s 15 -A 500 2200 0 0 0 0)
|
||||
|
|
|
@ -339,8 +339,7 @@ int srsran_ue_sync_set_cell(srsran_ue_sync_t* q, srsran_cell_t cell)
|
|||
q->cell = cell;
|
||||
q->fft_size = srsran_symbol_sz(q->cell.nof_prb);
|
||||
q->sf_len = SRSRAN_SF_LEN(q->fft_size);
|
||||
srsran_sync_set_cp(&q->sfind, q->cell.cp);
|
||||
srsran_sync_set_cp(&q->strack, q->cell.cp);
|
||||
|
||||
if (cell.id == 1000) {
|
||||
/* If the cell is unkown, we search PSS/SSS in 5 ms */
|
||||
q->nof_recv_sf = 5;
|
||||
|
@ -376,6 +375,10 @@ int srsran_ue_sync_set_cell(srsran_ue_sync_t* q, srsran_cell_t cell)
|
|||
}
|
||||
}
|
||||
|
||||
// Set CP for find and track objects
|
||||
srsran_sync_set_cp(&q->sfind, cell.cp);
|
||||
srsran_sync_set_cp(&q->strack, cell.cp);
|
||||
|
||||
// When Cell ID is 1000, ue_sync receives nof_avg_find_frames frames in find state and does not go to tracking
|
||||
// state and is used to search a cell
|
||||
if (cell.id == 1000) {
|
||||
|
@ -393,9 +396,6 @@ int srsran_ue_sync_set_cell(srsran_ue_sync_t* q, srsran_cell_t cell)
|
|||
srsran_sync_set_cfo_ema_alpha(&q->strack, 0.1);
|
||||
|
||||
} else {
|
||||
q->sfind.cp = cell.cp;
|
||||
q->strack.cp = cell.cp;
|
||||
|
||||
srsran_sync_set_frame_type(&q->sfind, cell.frame_type);
|
||||
srsran_sync_set_frame_type(&q->strack, cell.frame_type);
|
||||
|
||||
|
|
|
@ -174,6 +174,25 @@ int srsran_ue_ul_set_cell(srsran_ue_ul_t* q, srsran_cell_t cell)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int srsran_ue_ul_set_cfr(srsran_ue_ul_t* q, const srsran_cfr_cfg_t* cfr)
|
||||
{
|
||||
if (q == NULL || cfr == NULL) {
|
||||
ERROR("Error, invalid inputs");
|
||||
return SRSRAN_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
// Copy the cfr config into the UE
|
||||
q->cfr_config = *cfr;
|
||||
|
||||
// Set the cfr for the fft's
|
||||
if (srsran_ofdm_set_cfr(&q->fft, &q->cfr_config) < SRSRAN_SUCCESS) {
|
||||
ERROR("Error setting the CFR for the fft");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_ue_ul_pregen_signals(srsran_ue_ul_t* q, srsran_ue_ul_cfg_t* cfg)
|
||||
{
|
||||
if (q->signals_pregenerated) {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
if(RF_FOUND)
|
||||
add_library(srsran_radio STATIC radio.cc channel_mapping.cc)
|
||||
target_link_libraries(srsran_radio srsran_rf srsran_common)
|
||||
INSTALL(TARGETS srsran_radio DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_radio DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
endif(RF_FOUND)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
|
|
@ -665,11 +665,11 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq)
|
|||
// Map carrier index to physical channel
|
||||
if (rx_channel_mapping.allocate_freq(carrier_idx, freq)) {
|
||||
channel_mapping::device_mapping_t device_mapping = rx_channel_mapping.get_device_mapping(carrier_idx);
|
||||
if (device_mapping.carrier_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid mapping RF channel %d to logical carrier %d on f_rx=%.1f MHz",
|
||||
device_mapping.carrier_idx,
|
||||
if (device_mapping.channel_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid mapping physical channel %d to logical carrier %d on f_rx=%.1f MHz (nof_channels_x_dev=%d, device_idx=%d)",
|
||||
device_mapping.channel_idx,
|
||||
carrier_idx,
|
||||
freq / 1e6);
|
||||
freq / 1e6, nof_channels_x_dev, device_mapping.device_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -684,7 +684,7 @@ void radio::set_rx_freq(const uint32_t& carrier_idx, const double& freq)
|
|||
cur_rx_freqs[device_mapping.carrier_idx] = freq;
|
||||
for (uint32_t i = 0; i < nof_antennas; i++) {
|
||||
channel_mapping::device_mapping_t dm = rx_channel_mapping.get_device_mapping(carrier_idx, i);
|
||||
if (dm.device_idx >= rf_devices.size() or dm.carrier_idx >= nof_channels_x_dev) {
|
||||
if (dm.device_idx >= rf_devices.size() or dm.channel_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid port mapping %d:%d to logical carrier %d on f_rx=%.1f MHz",
|
||||
dm.device_idx,
|
||||
dm.channel_idx,
|
||||
|
@ -804,9 +804,9 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq)
|
|||
// Map carrier index to physical channel
|
||||
if (tx_channel_mapping.allocate_freq(carrier_idx, freq)) {
|
||||
channel_mapping::device_mapping_t device_mapping = tx_channel_mapping.get_device_mapping(carrier_idx);
|
||||
if (device_mapping.carrier_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid mapping RF channel %d to logical carrier %d on f_tx=%.1f MHz",
|
||||
device_mapping.carrier_idx,
|
||||
if (device_mapping.channel_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid mapping physical channel %d to logical carrier %d on f_tx=%.1f MHz",
|
||||
device_mapping.channel_idx,
|
||||
carrier_idx,
|
||||
freq / 1e6);
|
||||
return;
|
||||
|
@ -823,7 +823,7 @@ void radio::set_tx_freq(const uint32_t& carrier_idx, const double& freq)
|
|||
cur_tx_freqs[device_mapping.carrier_idx] = freq;
|
||||
for (uint32_t i = 0; i < nof_antennas; i++) {
|
||||
device_mapping = tx_channel_mapping.get_device_mapping(carrier_idx, i);
|
||||
if (device_mapping.device_idx >= rf_devices.size() or device_mapping.carrier_idx >= nof_channels_x_dev) {
|
||||
if (device_mapping.device_idx >= rf_devices.size() or device_mapping.channel_idx >= nof_channels_x_dev) {
|
||||
logger.error("Invalid port mapping %d:%d to logical carrier %d on f_rx=%.1f MHz",
|
||||
device_mapping.device_idx,
|
||||
device_mapping.channel_idx,
|
||||
|
|
|
@ -32,4 +32,4 @@ set(SOURCES rlc.cc
|
|||
|
||||
add_library(srsran_rlc STATIC ${SOURCES})
|
||||
target_link_libraries(srsran_rlc srsran_common ${ATOMIC_LIBS})
|
||||
INSTALL(TARGETS srsran_rlc DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srsran_rlc DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
|
|
@ -86,14 +86,32 @@ bool rlc_am::configure(const rlc_config_t& cfg_)
|
|||
return false;
|
||||
}
|
||||
|
||||
RlcInfo("configured - t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
|
||||
"t_reordering=%d, t_status_prohibit=%d",
|
||||
cfg.am.t_poll_retx,
|
||||
cfg.am.poll_pdu,
|
||||
cfg.am.poll_byte,
|
||||
cfg.am.max_retx_thresh,
|
||||
cfg.am.t_reordering,
|
||||
cfg.am.t_status_prohibit);
|
||||
if (cfg.rat == srsran_rat_t::lte) {
|
||||
RlcInfo("AM LTE configured - t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, max_retx_thresh=%d, "
|
||||
"t_reordering=%d, t_status_prohibit=%d, tx_queue_length=%d",
|
||||
cfg.am.t_poll_retx,
|
||||
cfg.am.poll_pdu,
|
||||
cfg.am.poll_byte,
|
||||
cfg.am.max_retx_thresh,
|
||||
cfg.am.t_reordering,
|
||||
cfg.am.t_status_prohibit,
|
||||
cfg.tx_queue_length);
|
||||
} else if (cfg.rat == srsran_rat_t::nr) {
|
||||
RlcInfo("AM NR configured - tx_sn_field_length=%d, rx_sn_field_length=%d, "
|
||||
"t_poll_retx=%d, poll_pdu=%d, poll_byte=%d, "
|
||||
"max_retx_thresh=%d, t_reassembly=%d, t_status_prohibit=%di, tx_queue_length=%d",
|
||||
to_number(cfg.am_nr.tx_sn_field_length),
|
||||
to_number(cfg.am_nr.rx_sn_field_length),
|
||||
cfg.am_nr.t_poll_retx,
|
||||
cfg.am_nr.poll_pdu,
|
||||
cfg.am_nr.poll_byte,
|
||||
cfg.am_nr.max_retx_thresh,
|
||||
cfg.am_nr.t_reassembly,
|
||||
cfg.am_nr.t_status_prohibit,
|
||||
cfg.tx_queue_length);
|
||||
} else {
|
||||
RlcError("Invalid RAT at entity configuration");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -244,6 +262,25 @@ int rlc_am::rlc_am_base_tx::write_sdu(unique_byte_buffer_t sdu)
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
void rlc_am::rlc_am_base_tx::discard_sdu(uint32_t discard_sn)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
if (!tx_enabled) {
|
||||
return;
|
||||
}
|
||||
bool discarded = tx_sdu_queue.apply_first([&discard_sn, this](unique_byte_buffer_t& sdu) {
|
||||
if (sdu != nullptr && sdu->md.pdcp_sn == discard_sn) {
|
||||
tx_sdu_queue.queue.pop_func(sdu);
|
||||
sdu = nullptr;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Discard fails when the PDCP PDU is already in Tx window.
|
||||
RlcInfo("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn);
|
||||
}
|
||||
|
||||
void rlc_am::rlc_am_base_tx::set_bsr_callback(bsr_callback_t callback)
|
||||
{
|
||||
bsr_callback = callback;
|
||||
|
|
|
@ -232,7 +232,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n
|
|||
|
||||
// Bytes needed for retx
|
||||
if (not retx_queue.empty()) {
|
||||
rlc_amd_retx_t& retx = retx_queue.front();
|
||||
rlc_amd_retx_lte_t& retx = retx_queue.front();
|
||||
RlcDebug("Buffer state - retx - SN=%d, Segment: %s, %d:%d",
|
||||
retx.sn,
|
||||
retx.is_segment ? "true" : "false",
|
||||
|
@ -277,24 +277,6 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n
|
|||
}
|
||||
}
|
||||
|
||||
void rlc_am_lte_tx::discard_sdu(uint32_t discard_sn)
|
||||
{
|
||||
if (!tx_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool discarded = tx_sdu_queue.apply_first([&discard_sn, this](unique_byte_buffer_t& sdu) {
|
||||
if (sdu != nullptr && sdu->md.pdcp_sn == discard_sn) {
|
||||
tx_sdu_queue.queue.pop_func(sdu);
|
||||
sdu = nullptr;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Discard fails when the PDCP PDU is already in Tx window.
|
||||
RlcInfo("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn);
|
||||
}
|
||||
|
||||
bool rlc_am_lte_tx::sdu_queue_is_full()
|
||||
{
|
||||
return tx_sdu_queue.is_full();
|
||||
|
@ -380,11 +362,11 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn)
|
|||
|
||||
RlcInfo("Schedule SN=%d for retx", pdu.rlc_sn);
|
||||
|
||||
rlc_amd_retx_t& retx = retx_queue.push();
|
||||
retx.is_segment = false;
|
||||
retx.so_start = 0;
|
||||
retx.so_end = pdu.buf->N_bytes;
|
||||
retx.sn = pdu.rlc_sn;
|
||||
rlc_amd_retx_lte_t& retx = retx_queue.push();
|
||||
retx.is_segment = false;
|
||||
retx.so_start = 0;
|
||||
retx.so_end = pdu.buf->N_bytes;
|
||||
retx.sn = pdu.rlc_sn;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -470,7 +452,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
return -1;
|
||||
}
|
||||
|
||||
rlc_amd_retx_t retx = retx_queue.front();
|
||||
rlc_amd_retx_lte_t retx = retx_queue.front();
|
||||
|
||||
// Sanity check - drop any retx SNs not present in tx_window
|
||||
while (not tx_window.has_sn(retx.sn)) {
|
||||
|
@ -543,7 +525,7 @@ int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
return (ptr - payload) + tx_window[retx.sn].buf->N_bytes;
|
||||
}
|
||||
|
||||
int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx)
|
||||
int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_lte_t retx)
|
||||
{
|
||||
if (tx_window[retx.sn].buf == NULL) {
|
||||
RlcError("In build_segment: retx.sn=%d has null buffer", retx.sn);
|
||||
|
@ -983,7 +965,7 @@ void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
pdu.retx_count++;
|
||||
check_sn_reached_max_retx(i);
|
||||
|
||||
rlc_amd_retx_t& retx = retx_queue.push();
|
||||
rlc_amd_retx_lte_t& retx = retx_queue.push();
|
||||
srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i);
|
||||
retx.sn = i;
|
||||
retx.is_segment = false;
|
||||
|
@ -1107,7 +1089,7 @@ void rlc_am_lte_tx::debug_state()
|
|||
RlcDebug("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", vt_a, vt_ms, vt_s, poll_sn);
|
||||
}
|
||||
|
||||
int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx)
|
||||
int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_lte_t& retx)
|
||||
{
|
||||
if (!retx.is_segment) {
|
||||
if (tx_window.has_sn(retx.sn)) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,74 @@
|
|||
|
||||
namespace srsran {
|
||||
|
||||
/****************************************************************************
|
||||
* Container implementation for pack/unpack functions
|
||||
***************************************************************************/
|
||||
|
||||
rlc_am_nr_status_pdu_t::rlc_am_nr_status_pdu_t(rlc_am_nr_sn_size_t sn_size) : sn_size(sn_size)
|
||||
{
|
||||
nacks_.reserve(RLC_AM_NR_TYP_NACKS);
|
||||
}
|
||||
|
||||
void rlc_am_nr_status_pdu_t::reset()
|
||||
{
|
||||
cpt = rlc_am_nr_control_pdu_type_t::status_pdu;
|
||||
ack_sn = INVALID_RLC_SN;
|
||||
nacks_.clear();
|
||||
packed_size_ = rlc_am_nr_status_pdu_sizeof_header_ack_sn;
|
||||
}
|
||||
|
||||
void rlc_am_nr_status_pdu_t::push_nack(const rlc_status_nack_t& nack)
|
||||
{
|
||||
nacks_.push_back(nack);
|
||||
packed_size_ += nack_size(nack);
|
||||
}
|
||||
|
||||
bool rlc_am_nr_status_pdu_t::trim(uint32_t max_packed_size)
|
||||
{
|
||||
if (max_packed_size >= packed_size_) {
|
||||
// no trimming required
|
||||
return true;
|
||||
}
|
||||
if (max_packed_size < rlc_am_nr_status_pdu_sizeof_header_ack_sn) {
|
||||
// too little space for smallest possible status PDU (only header + ACK).
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove NACKs (starting from the back) until it fits into given space
|
||||
// note: when removing a NACK for a segment, we have to remove all other NACKs with the same SN as well,
|
||||
// see TS 38.322 Sec. 5.3.4:
|
||||
// "set the ACK_SN to the SN of the next not received RLC SDU
|
||||
// which is not indicated as missing in the resulting STATUS PDU."
|
||||
while (nacks_.size() > 0 && (max_packed_size < packed_size_ || nacks_.back().nack_sn == ack_sn)) {
|
||||
packed_size_ -= nack_size(nacks_.back());
|
||||
ack_sn = nacks_.back().nack_sn;
|
||||
nacks_.pop_back();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void rlc_am_nr_status_pdu_t::refresh_packed_size()
|
||||
{
|
||||
uint32_t packed_size = rlc_am_nr_status_pdu_sizeof_header_ack_sn;
|
||||
for (auto nack : nacks_) {
|
||||
packed_size += nack_size(nack);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t rlc_am_nr_status_pdu_t::nack_size(const rlc_status_nack_t& nack) const
|
||||
{
|
||||
uint32_t result = sn_size == rlc_am_nr_sn_size_t::size12bits ? rlc_am_nr_status_pdu_sizeof_nack_sn_ext_12bit_sn
|
||||
: rlc_am_nr_status_pdu_sizeof_nack_sn_ext_18bit_sn;
|
||||
if (nack.has_so) {
|
||||
result += rlc_am_nr_status_pdu_sizeof_nack_so;
|
||||
}
|
||||
if (nack.has_nack_range) {
|
||||
result += rlc_am_nr_status_pdu_sizeof_nack_range;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Header pack/unpack helper functions
|
||||
* Ref: 3GPP TS 38.322 v15.3.0 Section 6.2.2.4
|
||||
|
@ -150,6 +218,11 @@ uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, b
|
|||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Status PDU pack/unpack helper functions
|
||||
* Ref: 3GPP TS 38.322 v16.2.0 Section 6.2.2.5
|
||||
***************************************************************************/
|
||||
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status)
|
||||
{
|
||||
|
@ -160,8 +233,19 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
|
|||
const uint32_t nof_bytes,
|
||||
const rlc_am_nr_sn_size_t sn_size,
|
||||
rlc_am_nr_status_pdu_t* status)
|
||||
{
|
||||
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
|
||||
return rlc_am_nr_read_status_pdu_12bit_sn(payload, nof_bytes, status);
|
||||
} else { // 18bit SN
|
||||
return rlc_am_nr_read_status_pdu_18bit_sn(payload, nof_bytes, status);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status)
|
||||
{
|
||||
uint8_t* ptr = const_cast<uint8_t*>(payload);
|
||||
status->reset();
|
||||
|
||||
// fixed part
|
||||
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
|
||||
|
@ -172,58 +256,144 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
|
||||
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
|
||||
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
|
||||
ptr++;
|
||||
|
||||
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
|
||||
ptr++;
|
||||
|
||||
// read E1 flag
|
||||
uint8_t e1 = *ptr & 0x80;
|
||||
|
||||
// sanity check for reserved bits
|
||||
if ((*ptr & 0x7f) != 0) {
|
||||
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// all good, continue with next byte depending on E1
|
||||
ptr++;
|
||||
|
||||
while (e1 != 0) {
|
||||
// E1 flag set, read a NACK_SN
|
||||
rlc_status_nack_t nack = {};
|
||||
nack.nack_sn = (*ptr & 0xff) << 4;
|
||||
ptr++;
|
||||
|
||||
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
|
||||
ptr++;
|
||||
|
||||
// read E1 flag
|
||||
uint8_t e1 = *ptr & 0x80;
|
||||
e1 = *ptr & 0x08; // 1 = further NACKs follow
|
||||
uint8_t e2 = *ptr & 0x04; // 1 = set of {so_start, so_end} follows
|
||||
uint8_t e3 = *ptr & 0x02; // 1 = NACK range follows (i.e. NACK across multiple SNs)
|
||||
|
||||
// sanity check for reserved bits
|
||||
if ((*ptr & 0x7f) != 0) {
|
||||
if ((*ptr & 0x01) != 0) {
|
||||
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
|
||||
return 0;
|
||||
}
|
||||
nack.nack_sn |= (*ptr & 0xF0) >> 4;
|
||||
|
||||
ptr++;
|
||||
if (e2 != 0) {
|
||||
nack.has_so = true;
|
||||
nack.so_start = (*ptr) << 8;
|
||||
ptr++;
|
||||
nack.so_start |= (*ptr);
|
||||
ptr++;
|
||||
nack.so_end = (*ptr) << 8;
|
||||
ptr++;
|
||||
nack.so_end |= (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
if (e3 != 0) {
|
||||
nack.has_nack_range = true;
|
||||
nack.nack_range = (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
status->push_nack(nack);
|
||||
if (uint32_t(ptr - payload) > nof_bytes) {
|
||||
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status)
|
||||
{
|
||||
uint8_t* ptr = const_cast<uint8_t*>(payload);
|
||||
status->reset();
|
||||
|
||||
// fixed part
|
||||
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
|
||||
|
||||
// sanity check
|
||||
if (status->cpt != rlc_am_nr_control_pdu_type_t::status_pdu) {
|
||||
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status->ack_sn = (*ptr & 0x0F) << 14; // upper 4 bits of SN
|
||||
ptr++;
|
||||
|
||||
status->ack_sn |= (*ptr & 0xFF) << 6; // center 8 bits of SN
|
||||
ptr++;
|
||||
|
||||
status->ack_sn |= (*ptr & 0xFC) >> 2; // lower 6 bits of SN
|
||||
|
||||
// read E1 flag
|
||||
uint8_t e1 = *ptr & 0x02;
|
||||
|
||||
// sanity check for reserved bits
|
||||
if ((*ptr & 0x01) != 0) {
|
||||
fprintf(stderr, "Malformed PDU, reserved bit is set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// all good, continue with next byte depending on E1
|
||||
ptr++;
|
||||
|
||||
while (e1 != 0) {
|
||||
// E1 flag set, read a NACK_SN
|
||||
rlc_status_nack_t nack = {};
|
||||
|
||||
nack.nack_sn = (*ptr & 0xFF) << 10; // upper 8 bits of SN
|
||||
ptr++;
|
||||
nack.nack_sn |= (*ptr & 0xFF) << 2; // center 8 bits of SN
|
||||
ptr++;
|
||||
nack.nack_sn |= (*ptr & 0xC0) >> 6; // lower 2 bits of SN
|
||||
|
||||
e1 = *ptr & 0x20; // 1 = further NACKs follow
|
||||
uint8_t e2 = *ptr & 0x10; // 1 = set of {so_start, so_end} follows
|
||||
uint8_t e3 = *ptr & 0x08; // 1 = NACK range follows (i.e. NACK across multiple SNs)
|
||||
|
||||
// sanity check for reserved bits
|
||||
if ((*ptr & 0x07) != 0) {
|
||||
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// all good, continue with next byte depending on E1
|
||||
ptr++;
|
||||
|
||||
// reset number of acks
|
||||
status->N_nack = 0;
|
||||
|
||||
while (e1 != 0) {
|
||||
// E1 flag set, read a NACK_SN
|
||||
rlc_status_nack_t nack = {};
|
||||
nack.nack_sn = (*ptr & 0xff) << 4;
|
||||
if (e2 != 0) {
|
||||
nack.has_so = true;
|
||||
nack.so_start = (*ptr) << 8;
|
||||
ptr++;
|
||||
|
||||
e1 = *ptr & 0x08;
|
||||
uint8_t e2 = *ptr & 0x04;
|
||||
|
||||
// uint8_t len2 = (*ptr & 0xF0) >> 4;
|
||||
nack.nack_sn |= (*ptr & 0xF0) >> 4;
|
||||
status->nacks[status->N_nack] = nack;
|
||||
|
||||
nack.so_start |= (*ptr);
|
||||
ptr++;
|
||||
if (e2 != 0) {
|
||||
status->nacks[status->N_nack].has_so = true;
|
||||
status->nacks[status->N_nack].so_start = (*ptr) << 8;
|
||||
ptr++;
|
||||
status->nacks[status->N_nack].so_start |= (*ptr);
|
||||
ptr++;
|
||||
status->nacks[status->N_nack].so_end = (*ptr) << 8;
|
||||
ptr++;
|
||||
status->nacks[status->N_nack].so_end |= (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
status->N_nack++;
|
||||
if ((ptr - payload) > nof_bytes) {
|
||||
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
|
||||
return 0;
|
||||
}
|
||||
nack.so_end = (*ptr) << 8;
|
||||
ptr++;
|
||||
nack.so_end |= (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
if (e3 != 0) {
|
||||
nack.has_nack_range = true;
|
||||
nack.nack_range = (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
status->push_nack(nack);
|
||||
if (uint32_t(ptr - payload) > nof_bytes) {
|
||||
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,64 +409,134 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
|
|||
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
|
||||
const rlc_am_nr_sn_size_t sn_size,
|
||||
byte_buffer_t* pdu)
|
||||
{
|
||||
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
|
||||
return rlc_am_nr_write_status_pdu_12bit_sn(status_pdu, pdu);
|
||||
} else { // 18bit SN
|
||||
return rlc_am_nr_write_status_pdu_18bit_sn(status_pdu, pdu);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu)
|
||||
{
|
||||
uint8_t* ptr = pdu->msg;
|
||||
|
||||
// fixed header part
|
||||
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
|
||||
|
||||
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
|
||||
// write first 4 bit of ACK_SN
|
||||
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
|
||||
ptr++;
|
||||
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
|
||||
ptr++;
|
||||
// write first 4 bit of ACK_SN
|
||||
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
|
||||
ptr++;
|
||||
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
|
||||
ptr++;
|
||||
|
||||
// write E1 flag in octet 3
|
||||
if (status_pdu.N_nack > 0) {
|
||||
*ptr = 0x80;
|
||||
} else {
|
||||
*ptr = 0x00;
|
||||
}
|
||||
ptr++;
|
||||
// write E1 flag in octet 3
|
||||
if (status_pdu.nacks.size() > 0) {
|
||||
*ptr = 0x80;
|
||||
} else {
|
||||
*ptr = 0x00;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
if (status_pdu.N_nack > 0) {
|
||||
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
|
||||
// write first 8 bit of NACK_SN
|
||||
*ptr = (status_pdu.nacks[i].nack_sn >> 4) & 0xff;
|
||||
if (status_pdu.nacks.size() > 0) {
|
||||
for (uint32_t i = 0; i < status_pdu.nacks.size(); i++) {
|
||||
// write first 8 bit of NACK_SN
|
||||
*ptr = (status_pdu.nacks[i].nack_sn >> 4) & 0xff;
|
||||
ptr++;
|
||||
|
||||
// write remaining 4 bits of NACK_SN
|
||||
*ptr = (status_pdu.nacks[i].nack_sn & 0x0f) << 4;
|
||||
// Set E1 if necessary
|
||||
if (i < (uint32_t)(status_pdu.nacks.size() - 1)) {
|
||||
*ptr |= 0x08;
|
||||
}
|
||||
|
||||
if (status_pdu.nacks[i].has_so) {
|
||||
// Set E2
|
||||
*ptr |= 0x04;
|
||||
}
|
||||
|
||||
if (status_pdu.nacks[i].has_nack_range) {
|
||||
// Set E3
|
||||
*ptr |= 0x02;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
if (status_pdu.nacks[i].has_so) {
|
||||
(*ptr) = status_pdu.nacks[i].so_start >> 8;
|
||||
ptr++;
|
||||
|
||||
// write remaining 4 bits of NACK_SN
|
||||
*ptr = (status_pdu.nacks[i].nack_sn & 0x0f) << 4;
|
||||
// Set E1 if necessary
|
||||
if (i < (uint32_t)(status_pdu.N_nack - 1)) {
|
||||
*ptr |= 0x08;
|
||||
}
|
||||
|
||||
if (status_pdu.nacks[i].has_so) {
|
||||
// Set E2
|
||||
*ptr |= 0x04;
|
||||
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_start >> 8;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_start;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end >> 8;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end;
|
||||
}
|
||||
(*ptr) = status_pdu.nacks[i].so_start;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end >> 8;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end;
|
||||
ptr++;
|
||||
}
|
||||
if (status_pdu.nacks[i].has_nack_range) {
|
||||
(*ptr) = status_pdu.nacks[i].nack_range;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdu->N_bytes = ptr - pdu->msg;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t rlc_am_nr_write_status_pdu_18bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu)
|
||||
{
|
||||
uint8_t* ptr = pdu->msg;
|
||||
|
||||
// fixed header part
|
||||
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
|
||||
|
||||
*ptr |= (status_pdu.ack_sn >> 14) & 0x0F; // upper 4 bits of SN
|
||||
ptr++;
|
||||
*ptr = (status_pdu.ack_sn >> 6) & 0xFF; // center 8 bits of SN
|
||||
ptr++;
|
||||
*ptr = (status_pdu.ack_sn << 2) & 0xFC; // lower 6 bits of SN
|
||||
|
||||
// set E1 flag if necessary
|
||||
if (status_pdu.nacks.size() > 0) {
|
||||
*ptr |= 0x02;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
if (status_pdu.nacks.size() > 0) {
|
||||
for (uint32_t i = 0; i < status_pdu.nacks.size(); i++) {
|
||||
*ptr = (status_pdu.nacks[i].nack_sn >> 10) & 0xFF; // upper 8 bits of SN
|
||||
ptr++;
|
||||
*ptr = (status_pdu.nacks[i].nack_sn >> 2) & 0xFF; // center 8 bits of SN
|
||||
ptr++;
|
||||
*ptr = (status_pdu.nacks[i].nack_sn << 6) & 0xC0; // lower 2 bits of SN
|
||||
|
||||
if (i < (uint32_t)(status_pdu.nacks.size() - 1)) {
|
||||
*ptr |= 0x20; // Set E1
|
||||
}
|
||||
if (status_pdu.nacks[i].has_so) {
|
||||
*ptr |= 0x10; // Set E2
|
||||
}
|
||||
if (status_pdu.nacks[i].has_nack_range) {
|
||||
*ptr |= 0x08; // Set E3
|
||||
}
|
||||
|
||||
ptr++;
|
||||
if (status_pdu.nacks[i].has_so) {
|
||||
(*ptr) = status_pdu.nacks[i].so_start >> 8;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_start;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end >> 8;
|
||||
ptr++;
|
||||
(*ptr) = status_pdu.nacks[i].so_end;
|
||||
ptr++;
|
||||
}
|
||||
if (status_pdu.nacks[i].has_nack_range) {
|
||||
(*ptr) = status_pdu.nacks[i].nack_range;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 18bit SN
|
||||
*ptr |= (status_pdu.ack_sn >> 14) & 0x0f; // 4 bit ACK_SN
|
||||
ptr++;
|
||||
*ptr = status_pdu.ack_sn >> 8; // bit 3 - 10 of SN
|
||||
ptr++;
|
||||
*ptr = (status_pdu.ack_sn & 0xff); // remaining 6 bit of SN
|
||||
ptr++;
|
||||
}
|
||||
|
||||
pdu->N_bytes = ptr - pdu->msg;
|
||||
|
|
|
@ -307,7 +307,18 @@ int rlc_um_base::rlc_um_base_tx::try_write_sdu(unique_byte_buffer_t sdu)
|
|||
|
||||
void rlc_um_base::rlc_um_base_tx::discard_sdu(uint32_t discard_sn)
|
||||
{
|
||||
RlcWarning("RLC UM: Discard SDU not implemented yet.");
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
bool discarded = tx_sdu_queue.apply_first([&discard_sn, this](unique_byte_buffer_t& sdu) {
|
||||
if (sdu != nullptr && sdu->md.pdcp_sn == discard_sn) {
|
||||
tx_sdu_queue.queue.pop_func(sdu);
|
||||
sdu = nullptr;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Discard fails when the PDCP PDU is already in Tx window.
|
||||
RlcInfo("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn);
|
||||
}
|
||||
|
||||
bool rlc_um_base::rlc_um_base_tx::sdu_queue_is_full()
|
||||
|
|
|
@ -42,4 +42,4 @@ find_package(Threads REQUIRED)
|
|||
|
||||
add_library(srslog STATIC ${SOURCES})
|
||||
target_link_libraries(srslog ${CMAKE_THREAD_LIBS_INIT})
|
||||
INSTALL(TARGETS srslog DESTINATION ${LIBRARY_DIR})
|
||||
install(TARGETS srslog DESTINATION ${LIBRARY_DIR} OPTIONAL)
|
||||
|
|
|
@ -35,7 +35,7 @@ struct handler_instance {
|
|||
|
||||
// Handlers are added in a thread safe manner without using locks to avoid possible issues if a signal is emitted while
|
||||
// modifying the callback array.
|
||||
static constexpr unsigned max_handlers = 12;
|
||||
static constexpr unsigned max_handlers = 256;
|
||||
static handler_instance registered_handlers[max_handlers];
|
||||
static std::atomic<unsigned> num_handlers;
|
||||
|
||||
|
|
|
@ -225,6 +225,39 @@ int test_dl_nas_transport()
|
|||
return 0;
|
||||
}
|
||||
|
||||
// DL NAS transport with AMF-UE-NGAP-ID larger than 32bit
|
||||
int test_dl_nas_transport2()
|
||||
{
|
||||
uint8_t ngap_msg[] = {0x00, 0x04, 0x40, 0x42, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x06, 0x80, 0x03, 0x03,
|
||||
0xcf, 0x37, 0xd0, 0x00, 0x55, 0x00, 0x02, 0x00, 0x01, 0x00, 0x26, 0x00, 0x2b, 0x2a,
|
||||
0x7e, 0x00, 0x56, 0x00, 0x02, 0x00, 0x00, 0x21, 0xbc, 0x8d, 0xe5, 0x61, 0xf5, 0xb4,
|
||||
0xa7, 0x05, 0x8f, 0xdb, 0xe2, 0x3b, 0x4e, 0x21, 0xda, 0x45, 0x20, 0x10, 0x5a, 0xb8,
|
||||
0xd1, 0xdb, 0x13, 0x76, 0x80, 0x00, 0x1b, 0x1a, 0x8d, 0x3c, 0x98, 0x4c, 0x01, 0x06};
|
||||
// 00044042000003000a0006800303cf37d00055000200010026002b2a7e00560002000021bc8de561f5b4a7058fdbe23b4e21da4520105ab8d1db137680001b1a8d3c984c0106
|
||||
|
||||
cbit_ref bref(ngap_msg, sizeof(ngap_msg));
|
||||
ngap_pdu_c pdu;
|
||||
TESTASSERT(pdu.unpack(bref) == SRSASN_SUCCESS);
|
||||
|
||||
// Check Fields
|
||||
TESTASSERT(pdu.type().value == ngap_pdu_c::types_opts::init_msg);
|
||||
TESTASSERT(pdu.init_msg().proc_code == ASN1_NGAP_ID_DL_NAS_TRANSPORT);
|
||||
TESTASSERT(pdu.init_msg().crit.value == crit_opts::ignore);
|
||||
TESTASSERT(pdu.init_msg().value.type().value == ngap_elem_procs_o::init_msg_c::types_opts::dl_nas_transport);
|
||||
|
||||
auto& dl_nas = pdu.init_msg().value.dl_nas_transport();
|
||||
// Field 0
|
||||
TESTASSERT_EQ(12948813776, dl_nas->amf_ue_ngap_id.value);
|
||||
|
||||
// ...
|
||||
// Field 2
|
||||
TESTASSERT(dl_nas->nas_pdu.value.size() == 42);
|
||||
|
||||
TESTASSERT(ceil(bref.distance(ngap_msg) / 8.0) == sizeof(ngap_msg));
|
||||
TESTASSERT(test_pack_unpack_consistency(pdu) == SRSASN_SUCCESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_ul_ran_status_transfer()
|
||||
{
|
||||
uint8_t ngap_msg[] = {0x00, 0x2e, 0x40, 0x3c, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x55, 0x00,
|
||||
|
@ -355,6 +388,7 @@ int main()
|
|||
test_ngsetup_response();
|
||||
test_init_ue_msg();
|
||||
test_dl_nas_transport();
|
||||
test_dl_nas_transport2();
|
||||
test_ul_ran_status_transfer();
|
||||
test_ue_context_release();
|
||||
test_ue_context_release_complete();
|
||||
|
|
|
@ -230,11 +230,11 @@ int rlc_am_nr_pdu_test6()
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
///< Control PDU tests
|
||||
///< Control PDU tests (12bit SN)
|
||||
// Status PDU for 12bit SN with ACK_SN=2065 and no further NACK_SN (E1 bit not set)
|
||||
int rlc_am_nr_control_pdu_test1()
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test1()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU test 1");
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test 1");
|
||||
const int len = 3;
|
||||
std::array<uint8_t, len> tv = {0x08, 0x11, 0x00};
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
@ -242,10 +242,10 @@ int rlc_am_nr_control_pdu_test1()
|
|||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu = {};
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 2065);
|
||||
TESTASSERT(status_pdu.N_nack == 0);
|
||||
TESTASSERT(status_pdu.nacks.size() == 0);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
@ -262,9 +262,9 @@ int rlc_am_nr_control_pdu_test1()
|
|||
}
|
||||
|
||||
// Status PDU for 12bit SN with ACK_SN=2065 and NACK_SN=273 (E1 bit set)
|
||||
int rlc_am_nr_control_pdu_test2()
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test2()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU test 2");
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test 2");
|
||||
const int len = 5;
|
||||
std::array<uint8_t, len> tv = {0x08, 0x11, 0x80, 0x11, 0x10};
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
@ -272,10 +272,10 @@ int rlc_am_nr_control_pdu_test2()
|
|||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu = {};
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 2065);
|
||||
TESTASSERT(status_pdu.N_nack == 1);
|
||||
TESTASSERT(status_pdu.nacks.size() == 1);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
|
||||
|
||||
// reset status PDU
|
||||
|
@ -283,7 +283,7 @@ int rlc_am_nr_control_pdu_test2()
|
|||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &pdu) == SRSRAN_SUCCESS);
|
||||
// TESTASSERT(pdu.N_bytes == tv.size());
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
|
||||
|
@ -294,9 +294,9 @@ int rlc_am_nr_control_pdu_test2()
|
|||
|
||||
// Status PDU for 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275, SO_START=5, SO_END=0xFFFF
|
||||
// E1 and E2 bit set on first NACK, only E2 on second.
|
||||
int rlc_am_nr_control_pdu_test3()
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test3()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU test 3");
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test 3");
|
||||
const int len = 15;
|
||||
std::array<uint8_t, len> tv = {
|
||||
0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x34, 0x00, 0x05, 0xFF, 0xFF};
|
||||
|
@ -305,10 +305,10 @@ int rlc_am_nr_control_pdu_test3()
|
|||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu = {};
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 2065);
|
||||
TESTASSERT(status_pdu.N_nack == 2);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
|
||||
TESTASSERT(status_pdu.nacks[0].so_start == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].so_end == 5);
|
||||
|
@ -331,9 +331,9 @@ int rlc_am_nr_control_pdu_test3()
|
|||
|
||||
// Status PDU for 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275
|
||||
// E1 and E2 bit set on first NACK, neither E1 or E2 on the second.
|
||||
int rlc_am_nr_control_pdu_test4()
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test4()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU test 4");
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test 4");
|
||||
const int len = 11;
|
||||
std::array<uint8_t, len> tv = {0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x30};
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
@ -341,10 +341,10 @@ int rlc_am_nr_control_pdu_test4()
|
|||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu = {};
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 2065);
|
||||
TESTASSERT(status_pdu.N_nack == 2);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
|
||||
TESTASSERT(status_pdu.nacks[0].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[0].so_start == 2);
|
||||
|
@ -368,9 +368,9 @@ int rlc_am_nr_control_pdu_test4()
|
|||
// Malformed Status PDU, with E1 still set at the end of the PDU
|
||||
// 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275, SO_START=5, SO_END=0xFFFF
|
||||
// E1 and E2 bit set on first NACK, only E2 on second.
|
||||
int rlc_am_nr_control_pdu_test5()
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test5()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU test 5");
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test 5");
|
||||
const int len = 15;
|
||||
std::array<uint8_t, len> tv = {
|
||||
0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x3c, 0x00, 0x05, 0xFF, 0xFF};
|
||||
|
@ -379,12 +379,562 @@ int rlc_am_nr_control_pdu_test5()
|
|||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu = {};
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Status PDU for 12bit SN with ACK_SN=2065,
|
||||
// NACK range0: 3 full SDUs, NACK_SN=273..275
|
||||
// NACK range1: missing segment sequence across 4 SDUs
|
||||
// starting at NACK_SN=276, SO_START=2,
|
||||
// ending at NACK_SN=279, SO_END=5
|
||||
// E1 and E3 bit set on first NACK, E2 and E3 bit set on the second.
|
||||
int rlc_am_nr_control_pdu_12bit_sn_test_nack_range()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (12bit SN) test NACK range");
|
||||
const int len = 13;
|
||||
std::array<uint8_t, len> tv = {0x08, // D/C | 3CPT | 4ACK_SN_upper
|
||||
0x11, // 8ACK_SN_lower
|
||||
0x80, // E1 | 7R
|
||||
0x11, // 8NACK_SN_upper
|
||||
0x1a, // 4NACK_SN_lower | E1 | E2 | E3 | R
|
||||
0x03, // 8NACK_range
|
||||
0x11, // 8NACK_SN_upper
|
||||
0x46, // 4NACK_SN_lower | E1 | E2 | E3 | R
|
||||
0x00, // 8SO_START_upper
|
||||
0x02, // 8SO_START_lower
|
||||
0x00, // 8SO_END_upper
|
||||
0x05, // 8SO_END_lower
|
||||
0x04}; // 8NACK_range
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size12bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 2065);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
|
||||
TESTASSERT(status_pdu.nacks[0].has_so == false);
|
||||
TESTASSERT(status_pdu.nacks[0].has_nack_range == true);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_range == 3);
|
||||
|
||||
TESTASSERT(status_pdu.nacks[1].nack_sn == 276);
|
||||
TESTASSERT(status_pdu.nacks[1].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[1].so_start == 2);
|
||||
TESTASSERT(status_pdu.nacks[1].so_end == 5);
|
||||
TESTASSERT(status_pdu.nacks[1].has_nack_range == true);
|
||||
TESTASSERT(status_pdu.nacks[1].nack_range == 4);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Test status PDU for correct trimming and estimation of packed size
|
||||
// 1) Test init, copy and reset
|
||||
// 2) Test step-wise growth and trimming of status PDU while covering several corner cases
|
||||
int rlc_am_nr_control_pdu_test_trimming(rlc_am_nr_sn_size_t sn_size)
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU ({} bit SN) test trimming", to_number(sn_size));
|
||||
|
||||
// status PDU with no NACKs
|
||||
{
|
||||
constexpr uint32_t min_size = 3;
|
||||
srsran::byte_buffer_t pdu;
|
||||
rlc_am_nr_status_pdu_t status_pdu(sn_size);
|
||||
|
||||
status_pdu.ack_sn = 99;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, min_size); // minimum size
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, min_size);
|
||||
|
||||
rlc_am_nr_status_pdu_t status_pdu_copy = status_pdu;
|
||||
TESTASSERT_EQ(status_pdu_copy.ack_sn, 99);
|
||||
TESTASSERT_EQ(status_pdu_copy.packed_size, min_size); // minimum size
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu_copy, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, min_size);
|
||||
|
||||
status_pdu.reset();
|
||||
|
||||
status_pdu.ack_sn = 77;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, min_size); // should still have minimum size
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, min_size);
|
||||
|
||||
TESTASSERT_EQ(status_pdu_copy.ack_sn, 99); // shouldn't have changed
|
||||
TESTASSERT_EQ(status_pdu_copy.packed_size, min_size); // minimum size
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu_copy, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, min_size);
|
||||
}
|
||||
|
||||
// status PDU with multiple NACKs
|
||||
// expect: ACK=77, NACKs=[12][14][17 50:99][17 150:199][17 250:299][19][21 333:111 r5][27 444:666 r3]
|
||||
{
|
||||
constexpr uint32_t min_size = 3;
|
||||
const uint32_t nack_size = sn_size == rlc_am_nr_sn_size_t::size12bits ? 2 : 3;
|
||||
constexpr uint32_t so_size = 4;
|
||||
constexpr uint32_t range_size = 1;
|
||||
uint32_t expected_size = min_size;
|
||||
srsran::byte_buffer_t pdu;
|
||||
rlc_am_nr_status_pdu_t status_pdu(sn_size);
|
||||
|
||||
status_pdu.ack_sn = 77;
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 12;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 14;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 17;
|
||||
nack.has_so = true;
|
||||
nack.so_start = 50;
|
||||
nack.so_end = 99;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size + so_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 17;
|
||||
nack.has_so = true;
|
||||
nack.so_start = 150;
|
||||
nack.so_end = 199;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size + so_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 17;
|
||||
nack.has_so = true;
|
||||
nack.so_start = 250;
|
||||
nack.so_end = 299;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size + so_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 19;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 21;
|
||||
nack.has_so = true;
|
||||
nack.so_start = 333;
|
||||
nack.so_end = 111;
|
||||
nack.has_nack_range = true;
|
||||
nack.nack_range = 5;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size + so_size + range_size;
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
{
|
||||
rlc_status_nack_t nack;
|
||||
nack.nack_sn = 27;
|
||||
nack.has_so = true;
|
||||
nack.so_start = 444;
|
||||
nack.so_end = 666;
|
||||
nack.has_nack_range = true;
|
||||
nack.nack_range = 3;
|
||||
status_pdu.push_nack(nack);
|
||||
}
|
||||
expected_size += nack_size + so_size + range_size;
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 77);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=77, NACKs=[12][14][17 50:99][17 150:199][17 250:299][19][21 333:111 r5][27 444:666 r3]
|
||||
|
||||
// create a copy, check content
|
||||
rlc_am_nr_status_pdu_t status_pdu_copy = status_pdu;
|
||||
TESTASSERT_EQ(status_pdu_copy.ack_sn, 77);
|
||||
TESTASSERT_EQ(status_pdu_copy.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu_copy, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=77, NACKs=[12][14][17 50:99][17 150:199][17 250:299][19][21 333:111 r5][27 444:666 r3]
|
||||
|
||||
// trim to much larger size: nothing should change
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size * 2), true);
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 77);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// trim to exact size: nothing should change
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size), true);
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 77);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// trim to (expected_size - 1): this should remove the last NACK and update ACK accordingly
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size - 1), true);
|
||||
expected_size -= nack_size + so_size + range_size;
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 27);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=27, NACKs=[12][14][17 50:99][17 150:199][17 250:299][19][21 333:111 r5]
|
||||
|
||||
// trim to (expected_size - last two NACKs): this should remove the last NACK and update ACK accordingly
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size - (2 * nack_size + so_size + range_size)), true);
|
||||
expected_size -= 2 * nack_size + so_size + range_size;
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 19);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=19, NACKs=[12][14][17 50:99][17 150:199][17 250:299]
|
||||
|
||||
// trim to (expected_size - 1): this should remove the last NACK and all other NACKs with the same SN
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size - 1), true);
|
||||
expected_size -= 3 * (nack_size + so_size);
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 17);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=17, NACKs=[12][14]
|
||||
|
||||
// trim to impossible size = 1: this should report a failure without changes of the PDU
|
||||
TESTASSERT_EQ(status_pdu.trim(1), false);
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 17);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=17, NACKs=[12][14]
|
||||
|
||||
// trim to minimum size: this should remove all NACKs and update ACK to the SN of the first NACK
|
||||
expected_size = min_size;
|
||||
TESTASSERT_EQ(status_pdu.trim(expected_size), true);
|
||||
TESTASSERT_EQ(status_pdu.ack_sn, 12);
|
||||
TESTASSERT_EQ(status_pdu.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
|
||||
// current state: ACK=12, NACKs empty
|
||||
|
||||
// check the copy again - should be unchanged if not a shallow copy
|
||||
TESTASSERT_EQ(status_pdu_copy.ack_sn, 77);
|
||||
TESTASSERT_EQ(status_pdu_copy.packed_size, expected_size);
|
||||
TESTASSERT_EQ(rlc_am_nr_write_status_pdu(status_pdu_copy, sn_size, &pdu), SRSRAN_SUCCESS);
|
||||
TESTASSERT_EQ(pdu.N_bytes, expected_size);
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
///< Control PDU tests (18bit SN)
|
||||
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 and no further NACK_SN (E1 bit not set)
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test1()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test 1");
|
||||
const int len = 3;
|
||||
std::array<uint8_t, len> tv = {0x0E, 0x66, 0x64};
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 235929);
|
||||
TESTASSERT(status_pdu.nacks.size() == 0);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set)
|
||||
// and NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test2()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test 2");
|
||||
const int len = 6;
|
||||
std::array<uint8_t, len> tv = {0x0E, 0x66, 0x66, 0xD9, 0x99, 0x80};
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 235929);
|
||||
TESTASSERT(status_pdu.nacks.size() == 1);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
|
||||
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
|
||||
// SO_START=2, SO_END=5,
|
||||
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 (E2 bit set),
|
||||
// SO_START=5, SO_END=0xFFFF
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test3()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test 3");
|
||||
const int len = 17;
|
||||
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
|
||||
0b01100110, // 8ACK_SN_center
|
||||
0b01100110, // 6ACK_SN_lower | E1 | R
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10011001, // 8NACK_SN_center
|
||||
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x02, // 8SO_START_lower
|
||||
0x00, // 8SO_END_upper
|
||||
0x05, // 8SO_END_lower
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10111111, // 8NACK_SN_center
|
||||
0b11010000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x05, // 8SO_START_lower
|
||||
0xFF, // 8SO_END_upper
|
||||
0xFF}; // 8SO_END_lower
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 235929);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
|
||||
TESTASSERT(status_pdu.nacks[0].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[0].so_start == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].so_end == 5);
|
||||
TESTASSERT(status_pdu.nacks[1].nack_sn == 222975);
|
||||
TESTASSERT(status_pdu.nacks[1].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[1].so_start == 5);
|
||||
TESTASSERT(status_pdu.nacks[1].so_end == 0xFFFF);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
|
||||
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
|
||||
// SO_START=2, SO_END=5,
|
||||
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 (E1 and E2 bit not set),
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test4()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test 4");
|
||||
const int len = 13;
|
||||
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
|
||||
0b01100110, // 8ACK_SN_center
|
||||
0b01100110, // 6ACK_SN_lower | E1 | R
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10011001, // 8NACK_SN_center
|
||||
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x02, // 8SO_START_lower
|
||||
0x00, // 8SO_END_upper
|
||||
0x05, // 8SO_END_lower
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10111111, // 8NACK_SN_center
|
||||
0b11000000}; // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 235929);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
|
||||
TESTASSERT(status_pdu.nacks[0].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[0].so_start == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].so_end == 5);
|
||||
TESTASSERT(status_pdu.nacks[1].nack_sn == 222975);
|
||||
TESTASSERT(status_pdu.nacks[1].has_so == false);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Malformed Status PDU, similar to test3 but with E1 still set at the end of the PDU
|
||||
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
|
||||
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
|
||||
// SO_START=2, SO_END=5,
|
||||
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 ([!E1!] and E2 bit set),
|
||||
// SO_START=5, SO_END=0xFFFF
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test5()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test 5");
|
||||
const int len = 17;
|
||||
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
|
||||
0b01100110, // 8ACK_SN_center
|
||||
0b01100110, // 6ACK_SN_lower | E1 | R
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10011001, // 8NACK_SN_center
|
||||
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x02, // 8SO_START_lower
|
||||
0x00, // 8SO_END_upper
|
||||
0x05, // 8SO_END_lower
|
||||
0b11011001, // 8NACK_SN_upper
|
||||
0b10111111, // 8NACK_SN_center
|
||||
0b11110000, // 2NACK_SN_lower | [!E1!] | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x05, // 8SO_START_lower
|
||||
0xFF, // 8SO_END_upper
|
||||
0xFF}; // 8SO_END_lower
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Status PDU for 18bit SN with ACK_SN=200977=0x31111=0b11 0001 0001 0001 0001,
|
||||
// NACK range0: 3 full SDUs, NACK_SN=69905=0x11111=0b01 0001 0001 0001 0001
|
||||
// NACK range1: missing segment sequence across 4 SDUs
|
||||
// starting at NACK_SN=69913=0x11119=0b01 0001 0001 0001 1001, SO_START=2,
|
||||
// ending at NACK_SN=69916, SO_END=5
|
||||
// E1 and E3 bit set on first NACK, E2 and E3 bit set on the second.
|
||||
int rlc_am_nr_control_pdu_18bit_sn_test_nack_range()
|
||||
{
|
||||
test_delimit_logger delimiter("Control PDU (18bit SN) test NACK range");
|
||||
const int len = 15;
|
||||
std::array<uint8_t, len> tv = {0b00001100, // D/C | 3CPT | 4ACK_SN_upper
|
||||
0b01000100, // 8ACK_SN_center
|
||||
0b01000110, // 6ACK_SN_lower | E1 | R
|
||||
0b01000100, // 8NACK_SN_upper
|
||||
0b01000100, // 8NACK_SN_center
|
||||
0b01101000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x03, // 8NACK_range
|
||||
0b01000100, // 8NACK_SN_upper
|
||||
0b01000110, // 8NACK_SN_center
|
||||
0b01011000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
|
||||
0x00, // 8SO_START_upper
|
||||
0x02, // 8SO_START_lower
|
||||
0x00, // 8SO_END_upper
|
||||
0x05, // 8SO_END_lower
|
||||
0x04}; // 8NACK_range
|
||||
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
|
||||
|
||||
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
|
||||
|
||||
// unpack PDU
|
||||
rlc_am_nr_status_pdu_t status_pdu(srsran::rlc_am_nr_sn_size_t::size18bits);
|
||||
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(status_pdu.ack_sn == 200977);
|
||||
TESTASSERT(status_pdu.nacks.size() == 2);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_sn == 69905);
|
||||
TESTASSERT(status_pdu.nacks[0].has_so == false);
|
||||
TESTASSERT(status_pdu.nacks[0].has_nack_range == true);
|
||||
TESTASSERT(status_pdu.nacks[0].nack_range == 3);
|
||||
|
||||
TESTASSERT(status_pdu.nacks[1].nack_sn == 69913);
|
||||
TESTASSERT(status_pdu.nacks[1].has_so == true);
|
||||
TESTASSERT(status_pdu.nacks[1].so_start == 2);
|
||||
TESTASSERT(status_pdu.nacks[1].so_end == 5);
|
||||
TESTASSERT(status_pdu.nacks[1].has_nack_range == true);
|
||||
TESTASSERT(status_pdu.nacks[1].nack_range == 4);
|
||||
|
||||
// reset status PDU
|
||||
pdu.clear();
|
||||
|
||||
// pack again
|
||||
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(pdu.N_bytes == tv.size());
|
||||
|
||||
write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes);
|
||||
TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
static const struct option long_options[] = {{"pcap", no_argument, nullptr, 'p'}, {nullptr, 0, nullptr, 0}};
|
||||
|
@ -441,28 +991,73 @@ int main(int argc, char** argv)
|
|||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test1()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test1() failed.\n");
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test1()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test1() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test2()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test2() failed.\n");
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test2()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test2() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test3()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test3() failed.\n");
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test3()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test3() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test4()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test4() failed.\n");
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test4()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test4() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test5()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test5() failed.\n");
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test5()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test5() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_12bit_sn_test_nack_range()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test_nack_range() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test_trimming(rlc_am_nr_sn_size_t::size12bits)) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test_trimming(size12bits) failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test1()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test1() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test2()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test2() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test3()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test3() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test4()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test4() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test5()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test5() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_18bit_sn_test_nack_range()) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test_nack_range() failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
if (rlc_am_nr_control_pdu_test_trimming(rlc_am_nr_sn_size_t::size18bits)) {
|
||||
fprintf(stderr, "rlc_am_nr_control_pdu_test_trimming(size18bits) failed.\n");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue