From 6f290e71253830f5a3ff9ea34196b5cbbc66258c Mon Sep 17 00:00:00 2001 From: root <hongzhi18.wang@gmail.com> Date: Fri, 22 Sep 2017 15:51:03 +0200 Subject: [PATCH] UE add RF board ZC706+AD9371 Conflicts: cmake_targets/build_oai openair1/PHY/LTE_TRANSPORT/prach.c openair1/SCHED/phy_procedures_lte_ue.c targets/ARCH/COMMON/common_lib.h targets/RT/USER/lte-softmodem.c --- cmake_targets/CMakeLists.txt | 46 +- cmake_targets/build_oai | 95 +- cmake_targets/tools/build_helper | 30 + oaienv | 3 + openair1/PHY/LTE_TRANSPORT/dci_tools.c | 3 + openair1/PHY/LTE_TRANSPORT/initial_sync.c | 6 +- openair1/PHY/LTE_TRANSPORT/prach.c | 4 +- openair1/PHY/LTE_TRANSPORT/print_stats.c | 6 +- openair1/SCHED/phy_procedures_lte_ue.c | 28 +- openair2/RRC/LITE/rrc_UE.c | 2 +- openair2/RRC/LITE/rrc_eNB.c | 2 +- targets/ARCH/ADRV9371_ZC706/Makefile | 63 + .../USERSPACE/PROFILES/ADRV9371-W_test.ini | 337 +++++ .../USERSPACE/PROFILES/profile1-osc.ini | 85 ++ .../PROFILES/profile_rx30_Tx60_syr.txt | 285 ++++ .../ue.band7.tm1.PRB100.adrv9371-zc706.ini | 89 ++ ...7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini | 89 ++ .../ue.band7.tm1.PRB25.adrv9371-zc706.ini | 85 ++ .../ue.band7.tm1.PRB50.adrv9371-zc706.ini | 85 ++ targets/ARCH/ADRV9371_ZC706/readme.txt | 17 + .../ADRV9371_ZC706/slib/libadrv9371_zc706.so | Bin 0 -> 260713 bytes targets/ARCH/COMMON/common_lib.c | 6 + targets/ARCH/COMMON/common_lib.h | 12 + targets/COMMON/openairinterface5g_limits.h | 2 +- targets/RT/USER/lte-hwlat.c | 944 ++++++++++++ targets/RT/USER/lte-hwlat2.c | 1282 +++++++++++++++++ targets/SIMU/USER/oaisim_functions.c | 2 +- targets/build_oai.bash | 4 + 28 files changed, 3582 insertions(+), 30 deletions(-) create mode 100755 targets/ARCH/ADRV9371_ZC706/Makefile create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ADRV9371-W_test.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile1-osc.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB25.adrv9371-zc706.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB50.adrv9371-zc706.ini create mode 100644 targets/ARCH/ADRV9371_ZC706/readme.txt create mode 100755 targets/ARCH/ADRV9371_ZC706/slib/libadrv9371_zc706.so create mode 100755 targets/RT/USER/lte-hwlat.c create mode 100644 targets/RT/USER/lte-hwlat2.c diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 5182f597e3..c536d90ab6 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -484,7 +484,7 @@ include_directories ("${X2AP_DIR}") add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4") add_list1_option(NB_ANTENNAS_TX "4" "Number of antennas in transmission" "1" "2" "4") -add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "EXMIMO" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR") +add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "EXMIMO" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR" "OAI_ADRV9371_ZC706") add_list2_option(TRANSP_PRO "None" "Transport protocol type" "None" "ETHERNET") #NOKIA config enhancement @@ -507,6 +507,11 @@ set (SHLIB_LOADER_SOURCES ) # include RF devices / transport protocols library modules ###################################################################### +if (HWLAT) + add_definitions(-DHWLAT ) +endif() + + include_directories("${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/") include_directories ("${OPENAIR_TARGETS}/ARCH/EXMIMO/DEFS/") @@ -761,6 +766,9 @@ include_directories("${OPENAIR3_DIR}/UDP") include_directories("${OPENAIR3_DIR}/GTPV1-U") include_directories("${OPENAIR_DIR}/targets/COMMON") include_directories("${OPENAIR_DIR}/targets/ARCH/COMMON") +include_directories("${OPENAIR_DIR}/targets/ARCH/ADRV9371_ZC706/USERSPACE/LIB/") +include_directories("${OPENAIR_DIR}/targets/ARCH/ADRV9371_ZC706/USERSPACE/libini/") +include_directories("${OPENAIR_DIR}/targets/ARCH/ADRV9371_ZC706/DEFS/") include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/USERSPACE/LIB/") include_directories("${OPENAIR_DIR}/targets/ARCH/EXMIMO/DEFS") include_directories("${OPENAIR2_DIR}/ENB_APP") @@ -2063,6 +2071,38 @@ target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES}) target_link_libraries (lte-softmodem-nos1 ${T_LIB}) + +# lte-hwlat +################################################### +add_executable(lte-hwlat + ${HW_SOURCE} + ${OPENAIR_TARGETS}/RT/USER/lte-hwlat.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ) +target_link_libraries (lte-hwlat + -Wl,--start-group + -Wl,--end-group ) + +target_link_libraries (lte-hwlat rt pthread m ) +target_link_libraries (lte-hwlat ${CMAKE_DL_LIBS} ) +target_link_libraries (lte-hwlat ${OPENAIR_TARGETS}/ARCH/ADRV9371_ZC706/slib/libadrv9371_zc706.so ) + + +# lte-hwlat-test +################################################### +add_executable(lte-hwlat-test + ${HW_SOURCE} + ${OPENAIR1_DIR}/PHY/TOOLS/time_meas.c + ${OPENAIR_TARGETS}/RT/USER/lte-hwlat2.c + ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c + ) +target_link_libraries (lte-hwlat-test + -Wl,--start-group + -Wl,--end-group ) + +target_link_libraries (lte-hwlat-test rt pthread m ) +target_link_libraries (lte-hwlat-test ${CMAKE_DL_LIBS} ) + # lte-uesoftmodem is UE implementation ####################################### @@ -2379,10 +2419,10 @@ if (${T_TRACER}) #all "add_executable" definitions (except tests, rb_tool, updatefw) lte-softmodem lte-softmodem-nos1 oaisim oaisim_nos1 dlsim_tm4 dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim - pdcchsim pucchsim prachsim syncsim + pdcchsim pucchsim prachsim syncsim lte-hwlat #all "add_library" definitions ITTI RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB - oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif + oai_adrv9371_zc706devif oai_exmimodevif oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_eth_transpro FLPT_MSG ASYNC_IF FLEXRAN_AGENT HASHTABLE MSC UTIL OMG_SUMO SECU_OSA SECU_CN SCHED_LIB PHY L2 default_sched remote_sched RAL CN_UTILS diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 596b5aff72..d9cad35b9e 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -51,6 +51,7 @@ REL="Rel14" HW="None" TP="None" NOS1=0 +HW_LATENCY=0 EPC=0 VERBOSE_COMPILE=0 CFLAGS_PROCESSOR_USER="" @@ -104,12 +105,14 @@ Options Specify conf_nvram_path (default \"$conf_nvram_path\") --UE-gen-nvram [output path] Specify gen_nvram_path (default \"$gen_nvram_path\") +--HWLAT + Makes test program for haw latency tests -r | --3gpp-release default is Rel14, Rel8 limits the implementation to 3GPP Release 8 version Rel10 limits the implementation to 3GPP Release 10 version -w | --hardware - EXMIMO, USRP, BLADERF, ETHERNET, LMSSDR, None (Default) + EXMIMO, USRP, BLADERF, ETHERNET, LMSSDR, ADRV9371_ZC706, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport protocol ETHERNET , None @@ -234,13 +237,16 @@ function main() { shift 2;; -w | --hardware) HW="$2" #"${i#*=}" - # Use OAI_USRP as the key word USRP is used inside UHD driver - if [ "$HW" != "BLADERF" -a "$HW" != "USRP" -a "$HW" != "LMSSDR" -a "$HW" != "None" -a "$HW" != "EXMIMO" ] ; then + # Use OAI_USRP as the key word USRP is used inside UHD driver + if [ "$HW" != "BLADERF" -a "$HW" != "USRP" -a "$HW" != "LMSSDR" -a "$HW" != "None" -a "$HW" != "EXMIMO" -a "$HW" != "ADRV9371_ZC706" ] ; then echo_fatal "Unknown HW type $HW will exit..." else if [ "$HW" == "USRP" ] ; then HW="OAI_USRP" fi + if [ "$HW" == "ADRV9371_ZC706" ] ; then + HW="OAI_ADRV9371_ZC706" + fi if [ "$HW" == "BLADERF" ] ; then HW="OAI_BLADERF" fi @@ -297,6 +303,14 @@ function main() { NOS1=1 echo_info "Will compile without S1 interface" shift;; + --HWLAT) + HWLAT=1 + echo_info "Will compile hw latency test program" + shift;; + --HWLAT_TEST) + HWLAT_TEST=1 + echo_info "Will compile hw latency test program" + shift;; --verbose-compile) VERBOSE_COMPILE=1 echo_info "Will compile with verbose instructions" @@ -397,6 +411,12 @@ function main() { fi fi + if [ "$HWLAT" = "1" ] ; then + if [ "$HW" = "None" ] ; then + echo_info "No radio head has been selected (HW set to $HW)" + fi + fi + echo_info "RF HW set to $HW" #Now we set flags to enable deadline scheduler settings #By default: USRP: disable, @@ -409,6 +429,8 @@ function main() { DEADLINE_SCHEDULER_FLAG_USER="False" elif [ "$HW" = "OAI_USRP" ] ; then DEADLINE_SCHEDULER_FLAG_USER="False" + elif [ "$HW" = "OAI_ADRV9371_ZC706" ] ; then + DEADLINE_SCHEDULER_FLAG_USER="False" elif [ "$HW" = "OAI_BLADERF" ] ; then DEADLINE_SCHEDULER_FLAG_USER="False" elif [ "$HW" = "OAI_LMSSDR" ] ; then @@ -474,6 +496,10 @@ function main() { install_usrp_uhd_driver $UHD_IMAGES_DIR fi fi + if [ "$HW" == "OAI_ADRV9371_ZC706" ] ; then + echo_info "\nInstalling packages for ADRV9371_ZC706 support" + check_install_libiio_driver + fi if [ "$HW" == "OAI_BLADERF" ] ; then echo_info "installing packages for BLADERF support" check_install_bladerf_driver @@ -811,9 +837,65 @@ function main() { libtelnetsrv.so $dbin/libtelnetsrv.so fi + # HWLAT compilation + ##################### + if [ "$HWLAT" = "1" ] ; then + + hwlat_exec=lte-hwlat + hwlat_build_dir=lte-hwlat + + echo_info "Compiling $hwlat_exec ..." + + [ "$CLEAN" = "1" ] && rm -rf $DIR/lte-hwlat/build + mkdir -p $DIR/$hwlat_build_dir/build + cmake_file=$DIR/$hwlat_build_dir/CMakeLists.txt + echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file + echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file + echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file + echo 'set ( PACKAGE_NAME "\"lte-hwlat\"")' >> $cmake_file + echo "set ( DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file + echo "set ( CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file + echo "set ( HWLAT \"${HWLAT}\" )" >>$cmake_file + echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file + cd $DIR/$hwlat_build_dir/build + cmake .. + compilations \ + lte-hwlat lte-hwlat \ + lte-hwlat $dbin/lte-hwlat + + fi + + # HWLAT_TEST compilation + ##################### + if [ "$HWLAT_TEST" = "1" ] ; then + + hwlat_test_exec=lte-hwlat-test + hwlat_test_build_dir=lte-hwlat-test + + echo_info "Compiling $hwlat_test_exec ..." + + [ "$CLEAN" = "1" ] && rm -rf $DIR/lte-hwlat-test/build + mkdir -p $DIR/$hwlat_test_build_dir/build + cmake_file=$DIR/$hwlat_test_build_dir/CMakeLists.txt + echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file + echo "set ( CMAKE_BUILD_TYPE $CMAKE_BUILD_TYPE )" >> $cmake_file + echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file + echo 'set ( PACKAGE_NAME "\"lte-hwlat-test\"")' >> $cmake_file + echo "set ( DEADLINE_SCHEDULER \"${DEADLINE_SCHEDULER_FLAG_USER}\" )" >>$cmake_file + echo "set ( CPU_AFFINITY \"${CPU_AFFINITY_FLAG_USER}\" )" >>$cmake_file + echo "set ( HWLAT \"${HWLAT}\" )" >>$cmake_file + echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file + cd $DIR/$hwlat_test_build_dir/build + cmake .. + compilations \ + lte-hwlat-test lte-hwlat-test \ + lte-hwlat-test $dbin/lte-hwlat-test + + fi + # build RF device and transport protocol libraries ##################################### - if [ "$eNB" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$nrUE" = "1" ] ; then + if [ "$eNB" = "1" -o "$UE" = "1" -o "$gNB" = "1" -o "$nrUE" = "1" - o "$HWLAT" = "1" ] ; then build_dir=$build_dir @@ -831,6 +913,11 @@ function main() { ln -sf liboai_exmimodevif.so liboai_device.so ln -sf $dbin/liboai_exmimodevif.so.$REL $dbin/liboai_device.so echo_info "liboai_device.so is linked to EXMIMO device library" + elif [ "$HW" == "OAI_ADRV9371_ZC706" ] ; then + + ln -sf $OPENAIR_DIR/targets/ARCH/ADRV9371_ZC706/slib/libadrv9371_zc706.so liboai_device.so + + echo_info "liboai_device.so is linked to ADRV9371_ZC706 device library" elif [ "$HW" == "OAI_USRP" ] ; then compilations \ $build_dir oai_usrpdevif \ diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 2b8123c86b..4d95292f08 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -242,6 +242,36 @@ install_protobuf_c_from_source(){ ) >& $protobuf_c_install_log } +install_libiio_driver_from_source(){ + libiio_install_log=$OPENAIR_DIR/cmake_targets/log/libiio_install_log.txt + echo_info "\nInstalling LibIIO driver from sources. The log file for LibIIO driver installation is here: $libiio_install_log " + ( + cd /tmp + echo "Downloading LibIIO driver" + rm -rf /tmp/libiio + git clone https://github.com/analogdevicesinc/libiio.git + cd libiio + git checkout 2016_R2 + cmake ./ + make all + $SUDO make install + ) >& $libiio_install_log +} + +check_install_libiio_driver(){ + if [[ "$OS_DISTRO" == "ubuntu" ]]; then + $SUDO apt-get install -y --allow-unauthenticated libxml2 + $SUDO apt-get install -y --allow-unauthenticated libxml2-dev + $SUDO apt-get install -y --allow-unauthenticated bison + $SUDO apt-get install -y --allow-unauthenticated flex + $SUDO apt-get install -y --allow-unauthenticated libcdk5-dev + $SUDO apt-get install -y --allow-unauthenticated cmake + $SUDO apt-get install -y --allow-unauthenticated libaio-dev + $SUDO apt-get install -y --allow-unauthenticated libavahi-client-dev + install_libiio_driver_from_source + fi +} + install_usrp_uhd_driver_from_source(){ uhd_install_log=$OPENAIR_DIR/cmake_targets/log/uhd_install_log.txt echo_info "\nInstalling UHD driver from sources. The log file for UHD driver installation is here: $uhd_install_log " diff --git a/oaienv b/oaienv index f6b298debf..d9a540697b 100644 --- a/oaienv +++ b/oaienv @@ -17,3 +17,6 @@ alias oait='cd $OPENAIR_TARGETS' alias oailte='cd $OPENAIR_TARGETS/RT/USER' alias oais='cd $OPENAIR_TARGETS/SIMU/USER' alias oaiex='cd $OPENAIR_TARGETS/SIMU/EXAMPLES' + +export IIOD_REMOTE=192.168.121.32 + diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 4b73de6fcc..8f995e12e3 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -8118,6 +8118,9 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, // ulsch->n_DMRS2 = ((DCI0_5MHz_TDD_1_6_t *)dci_pdu)->cshift; +//printf("Format 0 DCI : ulsch (ue): AbsSubframe %d.%d nrb %d harq_pid %d round %d mcs %d\n",proc->frame_rx%1024,nr_tti_rx,ulsch->harq_processes[harq_pid]->nb_rb, + // harq_pid,ulsch->harq_processes[harq_pid]->round,ulsch->harq_processes[harq_pid]->mcs); + #ifdef UE_DEBUG_TRACE LOG_D(PHY,"Format 0 DCI : ulsch (ue): AbsSubframe %d.%d\n",proc->frame_rx%1024,subframe); diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c index 918696968b..ab987c4a4f 100644 --- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c @@ -554,7 +554,7 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) ue->frame_parms.nb_antenna_ports_eNB); #endif -#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) # if DISABLE_LOG_X printf("[UE %d] Frame %d Measured Carrier Frequency %.0f Hz (offset %d Hz)\n", ue->Mod_id, @@ -618,9 +618,11 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) #ifndef OAI_USRP #ifndef OAI_BLADERF #ifndef OAI_LMSSDR +#ifndef OAI_ADRV9371_ZC706 phy_adjust_gain(ue,ue->measurements.rx_power_avg_dB[0],0); #endif #endif +#endif #endif } @@ -629,9 +631,11 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) #ifndef OAI_USRP #ifndef OAI_BLADERF #ifndef OAI_LMSSDR +#ifndef OAI_ADRV9371_ZC706 phy_adjust_gain(ue,dB_fixed(ue->measurements.rssi),0); #endif #endif +#endif #endif } diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index b58aa91636..0c97a307af 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -636,7 +636,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 int i, prach_len; uint16_t first_nonzero_root_idx=0; -#if defined(EXMIMO) || defined(OAI_USRP) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706) prach_start = (ue->rx_offset+subframe*ue->frame_parms.samples_per_tti-ue->hw_timing_advance-ue->N_TA_offset); #ifdef PRACH_DEBUG LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id, @@ -1042,7 +1042,7 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 AssertFatal(prach_fmt<4, "prach_fmt4 not fully implemented" ); -#if defined(EXMIMO) || defined(OAI_USRP) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706) int j; int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*ue->frame_parms.samples_per_tti; LOG_I( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow ); diff --git a/openair1/PHY/LTE_TRANSPORT/print_stats.c b/openair1/PHY/LTE_TRANSPORT/print_stats.c index 9e328353a4..22b1adf3b9 100644 --- a/openair1/PHY/LTE_TRANSPORT/print_stats.c +++ b/openair1/PHY/LTE_TRANSPORT/print_stats.c @@ -42,7 +42,7 @@ #endif extern int mac_get_rrc_status(uint8_t Mod_id,uint8_t eNB_flag,uint8_t index); -#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) #include "common_lib.h" extern openair0_config_t openair0_cfg[]; #endif @@ -90,10 +90,10 @@ int dump_ue_stats(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc,char* buffer, int length #ifdef EXMIMO len += sprintf(&buffer[len], "[UE PROC] RX Gain %d dB (LNA %d, vga %d dB)\n",ue->rx_total_gain_dB, openair0_cfg[0].rxg_mode[0],(int)openair0_cfg[0].rx_gain[0]); #endif -#if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) len += sprintf(&buffer[len], "[UE PROC] RX Gain %d dB\n",ue->rx_total_gain_dB); #endif -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) len += sprintf(&buffer[len], "[UE_PROC] Frequency offset %d Hz, estimated carrier frequency %f Hz\n",ue->common_vars.freq_offset,openair0_cfg[0].rx_freq[0]-ue->common_vars.freq_offset); #endif len += sprintf(&buffer[len], "[UE PROC] UE mode = %s (%d)\n",mode_string[ue->UE_mode[0]],ue->UE_mode[0]); diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c index 2635649589..c73e14b288 100644 --- a/openair1/SCHED/phy_procedures_lte_ue.c +++ b/openair1/SCHED/phy_procedures_lte_ue.c @@ -76,7 +76,7 @@ extern double cpuf; void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id); -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; #endif @@ -158,7 +158,7 @@ void dump_dlsch_SI(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8_t s exit(-1); } -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) //unsigned int gain_table[31] = {100,112,126,141,158,178,200,224,251,282,316,359,398,447,501,562,631,708,794,891,1000,1122,1258,1412,1585,1778,1995,2239,2512,2818,3162}; /* unsigned int get_tx_amp_prach(int power_dBm, int power_max_dBm, int N_RB_UL) @@ -1202,7 +1202,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt int frame_tx = proc->frame_tx; int ulsch_start; int overflow=0; -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) int k,l; int dummy_tx_buffer[frame_parms->samples_per_tti] __attribute__((aligned(16))); #endif @@ -1213,7 +1213,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt #endif nsymb = (frame_parms->Ncp == 0) ? 14 : 12; -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)//this is the EXPRESS MIMO case +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)//this is the EXPRESS MIMO case ulsch_start = (ue->rx_offset+subframe_tx*frame_parms->samples_per_tti- ue->hw_timing_advance- ue->timing_advance- @@ -1231,7 +1231,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt ulsch_start = (frame_parms->samples_per_tti*subframe_tx)-ue->N_TA_offset; //-ue->timing_advance; #endif //else EXMIMO -//#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +//#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) if (empty_subframe) { //#if 1 @@ -1279,7 +1279,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) { if (frame_parms->Ncp == 1) PHY_ofdm_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size], -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) dummy_tx_buffer, #else &ue->common_vars.txdata[aa][ulsch_start], @@ -1290,7 +1290,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt CYCLIC_PREFIX); else { normal_prefix_mod(&ue->common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size], -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) dummy_tx_buffer, #else &ue->common_vars.txdata[aa][ulsch_start], @@ -1308,7 +1308,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt &ue->frame_parms); } -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) apply_7_5_kHz(ue,dummy_tx_buffer,0); apply_7_5_kHz(ue,dummy_tx_buffer,1); #else @@ -1317,7 +1317,7 @@ void ulsch_common_procedures(PHY_VARS_UE *ue, UE_rxtx_proc_t *proc, uint8_t empt #endif -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) overflow = ulsch_start - 9*frame_parms->samples_per_tti; @@ -1822,7 +1822,7 @@ void ue_ulsch_uespec_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB } ue->tx_total_RE[subframe_tx] = nb_rb*12; -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) tx_amp = get_tx_amp(ue->tx_power_dBm[subframe_tx], ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, @@ -1899,7 +1899,7 @@ void ue_srs_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uint8 Po_SRS = ue->tx_power_max_dBm; } -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) if (ue->mac_enabled==1) { tx_amp = get_tx_amp(Po_SRS, @@ -2182,7 +2182,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->tx_power_dBm[subframe_tx] = Po_PUCCH; ue->tx_total_RE[subframe_tx] = 12; -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) tx_amp = get_tx_amp(Po_PUCCH, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, @@ -2277,7 +2277,7 @@ void ue_pucch_procedures(PHY_VARS_UE *ue,UE_rxtx_proc_t *proc,uint8_t eNB_id,uin ue->tx_power_dBm[subframe_tx] = Po_PUCCH; ue->tx_total_RE[subframe_tx] = 12; -#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) +#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) tx_amp = get_tx_amp(Po_PUCCH, ue->tx_power_max_dBm, ue->frame_parms.N_RB_UL, @@ -2538,9 +2538,11 @@ void ue_measurement_procedures( #ifndef OAI_USRP #ifndef OAI_BLADERF #ifndef OAI_LMSSDR +#ifndef OAI_ADRV9371_ZC706 phy_adjust_gain (ue,dB_fixed(ue->measurements.rssi),0); #endif #endif +#endif #endif VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT); diff --git a/openair2/RRC/LITE/rrc_UE.c b/openair2/RRC/LITE/rrc_UE.c index 3edf230ac2..2a12def752 100644 --- a/openair2/RRC/LITE/rrc_UE.c +++ b/openair2/RRC/LITE/rrc_UE.c @@ -788,7 +788,7 @@ rrc_ue_establish_drb( RADIO_ACCESS_BEARER,Rlc_info_um); */ #ifdef PDCP_USE_NETLINK -# if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(LINK_ENB_PDCP_TO_GTPV1U) +# if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(LINK_ENB_PDCP_TO_GTPV1U) && !defined(OAI_ADRV9371_ZC706) ip_addr_offset3 = 0; ip_addr_offset4 = 1; LOG_I(OIP,"[UE %d] trying to bring up the OAI interface oai%d, IP 10.0.%d.%d\n", ue_mod_idP, ip_addr_offset3+ue_mod_idP, diff --git a/openair2/RRC/LITE/rrc_eNB.c b/openair2/RRC/LITE/rrc_eNB.c index 9faa686ef6..78d32697f3 100644 --- a/openair2/RRC/LITE/rrc_eNB.c +++ b/openair2/RRC/LITE/rrc_eNB.c @@ -5401,7 +5401,7 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id, ctxt_pP->frame, (int)DRB_configList->list.array[i]->drb_Identity); #if defined(PDCP_USE_NETLINK) && !defined(LINK_ENB_PDCP_TO_GTPV1U) // can mean also IPV6 since ether -> ipv6 autoconf -# if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) +# if !defined(OAI_NW_DRIVER_TYPE_ETHERNET) && !defined(EXMIMO) && !defined(OAI_USRP) && !defined(OAI_BLADERF) && !defined(ETHERNET) && !defined(OAI_ADRV9371_ZC706) LOG_I(OIP, "[eNB %d] trying to bring up the OAI interface oai%d\n", ctxt_pP->module_id, ctxt_pP->module_id); diff --git a/targets/ARCH/ADRV9371_ZC706/Makefile b/targets/ARCH/ADRV9371_ZC706/Makefile new file mode 100755 index 0000000000..5684c7b3bc --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/Makefile @@ -0,0 +1,63 @@ +# Creates shared library + +CC= gcc +CFLAGS+= -DADRV9371_ZC706 -DHWLAT -O0 -g3 -Wall -fmessage-length=0 -fPIC + +DROOT= ./USERSPACE +DIR= $(DROOT)/LIB + +IFLAGS+= -I$(DIR)/ \ + -I$(DROOT)/libini/ \ + -I../COMMON/ \ + -I/usr/include/ + +LDFLAGS+= -L/usr/lib/x86/64-linux-gnu/ \ + -lm -liio -ldl -lriffa + +OUTDIR= ./slib +TARGET= libadrv9371_zc706.so + +SRC= $(DIR)/adrv9371_dump.c \ + $(DIR)/adrv9371_helper.c \ + $(DIR)/adrv9371_self_test.c \ + $(DIR)/adrv9371_zc706_lib.c \ + $(DIR)/adrv9371_zc706_riffa_lib.c \ + $(DIR)/adrv9371_zc706_stats.c \ + $(DIR)/hw_init.c \ + $(DROOT)/libini/libini.c + +OBJ= $(OUTDIR)/adrv9371_dump.o \ + $(OUTDIR)/adrv9371_helper.o \ + $(OUTDIR)/adrv9371_self_test.o \ + $(OUTDIR)/adrv9371_zc706_lib.o \ + $(OUTDIR)/adrv9371_zc706_riffa_lib.o \ + $(OUTDIR)/adrv9371_zc706_stats.o \ + $(OUTDIR)/hw_init.o \ + $(OUTDIR)/libini.o + +all: lib + +dir: + mkdir -p $(OUTDIR) + +env: + set PATH=/usr/lib/:${PATH} + +obj: dir env + $(CC) -c $(CFLAGS) $(IFLAGS) $(SRC) + mv *.o $(OUTDIR) + +lib: dir obj + $(CC) -shared $(OBJ) -o $(OUTDIR)/$(TARGET) $(LDFLAGS) + +# exec: env +# $(CC) $(CFLAGS) $(IFLAGS) main.c $(SRC) -o lib.exe $(LDFLAGS) -lpthread + +.PHONY: clean + +clean: + rm -f $(OUTDIR)/*.o $(OUTDIR)/*~ + +rm: clean + rm -f $(OUTDIR)/$(TARGET) + rmdir $(OUTDIR) \ No newline at end of file diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ADRV9371-W_test.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ADRV9371-W_test.ini new file mode 100644 index 0000000000..c1861b2e8d --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ADRV9371-W_test.ini @@ -0,0 +1,337 @@ +[IIO Oscilloscope] +plugin.DMM.detached=0 +plugin.Debug.detached=0 +plugin.AD9371 Advanced.detached=0 +plugin.AD9371.detached=0 +startup_version_check=0 +test=1 + +[IIO Oscilloscope - Capture Window1] +fru_connect = 1 +test.message = Please ensure:\n • 30.72 MHz -> REF_CLK_IN (0dBm)\n • Rx1 <-> Tx1\n • Rx2 <-> Tx2 +domain=fft +sample_count=400 +fft_size=16384 +fft_avg=8 +fft_pwr_offset=0.000000 +graph_type=Lines +show_grid=1 +enable_auto_scale=1 +x_axis_min=-67.583626 +x_axis_max=67.576126 +y_axis_min=-130 +y_axis_max=3 +show_capture_options = 1 + +axi-ad9371-rx-obs-hpc.expanded=1 +axi-ad9371-rx-obs-hpc.active=0 +axi-ad9371-rx-obs-hpc.trigger_enabled=0 +axi-ad9371-rx-obs-hpc.voltage0_i.enabled=0 +axi-ad9371-rx-obs-hpc.voltage0_q.enabled=0 + +axi-ad9371-rx-hpc.expanded=1 +axi-ad9371-rx-hpc.active=1 +axi-ad9371-rx-hpc.voltage0_i.enabled=1 +axi-ad9371-rx-hpc.voltage0_q.enabled=1 +axi-ad9371-rx-hpc.voltage1_i.enabled=0 +axi-ad9371-rx-hpc.voltage1_q.enabled=0 + +marker_type = Single Tone Markers +marker.0 = 9525 +marker.1 = 8192 +marker.2 = 10859 +marker.3 = 12193 +marker.4 = 13526 +marker.5 = 14859 +capture_started=0 + +[DMM] +device_list = ad7291 0 +device_list = ad9371-phy 0 +device_list = xadc 0 +running = No + +# temp between 20C and 55C (in 0.25C units) +test.ad7291.in_temp0_raw.int = 80 220 + +# See the production testing wiki docs [1] for how these values are calculated. +# [1]: (https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz/testing#voltage) + +# scale = 0.610351562 +# All nominal voltages +/- 2.5% + +# 0 INPUT_VOLTAGE 12V - V(Drop Diode) 56/10 +test.ad7291.in_voltage0_raw.int = 2710 2850 + +# 1 VOUT2_1V3_DIG 1 +test.ad7291.in_voltage1_raw.int = 2077 2183 + +# 2 VDD_IF 10/10 +test.ad7291.in_voltage2_raw.int = 1997 2099 + +# 3 VOUT3_3V3 10/10 +test.ad7291.in_voltage3_raw.int = 2636 2770 + +# 5 VOUT4_1V8 1 +test.ad7291.in_voltage5_raw.int = 2875 3023 + +# 7 VOUT1_1V3_ANLG 1 +test.ad7291.in_voltage7_raw.int = 2077 2183 + + +# Test AD9528 lock status - Requires 30.720 MHz reference clock! +test.ad9528-1.pll1_reference_clk_a_present.int = 1 1 +test.ad9528-1.pll1_locked.int = 1 1 +test.ad9528-1.pll2_locked.int = 1 1 + + +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = INTERNALCALS +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2500000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2600000000 +ad9371-phy.out_voltage1_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 1 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_gain_control_mode = automatic +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = automatic +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2600000000 +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 1 +ad9371-phy.out_voltage0_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.ensm_mode = radio_on +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 10001402 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1001265 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 10001402 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 10001402 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 40001860 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1001265 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 10001402 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 40001860 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +dds_mode_tx1 = 0 +dds_mode_tx2 = 0 +SYNC_RELOAD = 1 + +# test receiver at 1GHz to 5 GHz +# SEQ FIRST INCREMENT LAST +<SEQ> i 1000000000 5000000000 5000000000 + +[IIO Oscilloscope - Capture Window1] +# wait for device to settle +marker_type = Peak Markers +capture_started = 0 +cycle = 1000 +axi-ad9371-rx-hpc.voltage0_i.enabled=1 +axi-ad9371-rx-hpc.voltage0_q.enabled=1 +axi-ad9371-rx-hpc.voltage1_i.enabled=0 +axi-ad9371-rx-hpc.voltage1_q.enabled=0 +cycle = 1000 + +[AD9371] +ad9371-phy.out_altvoltage1_TX_LO_frequency = <i> +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = {{<i>} + {100000000}} +ad9371-phy.out_altvoltage0_RX_LO_frequency = {{<i>} + {100000000}} +dds_mode_tx1 = 0 +dds_mode_tx2 = 0 +SYNC_RELOAD = 1 + +[IIO Oscilloscope - Capture Window1] +# wait for device to settle +capture_started = 1 +cycle = 3000 + +[AD9371] +# channels should be off, so RSSI should be low +test.ad9371-phy.in_voltage0_rssi.int = 44 45 +test.ad9371-phy.in_voltage1_rssi.int = 44 45 + +# and gain is high +test.ad9371-phy.in_voltage0_hardwaregain.double = 30.0 31.0 +test.ad9371-phy.in_voltage0_hardwaregain.double = 30.0 31.0 + +# set Tx and Rx to be the same +ad9371-phy.out_altvoltage0_RX_LO_frequency = <i> +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +SYNC_RELOAD = 1 + +[IIO Oscilloscope - Capture Window1] +# wait for device to settle +marker_type = Single Tone Markers +cycle = 3000 + +[AD9371] + +ad9371-phy.out_voltage0_hardwaregain = 0.000000 dB +ad9371-phy.out_voltage1_hardwaregain = 0.000000 dB + +# channels should be on, so RSSI should be high +test.ad9371-phy.in_voltage0_rssi.int = 3 12 +test.ad9371-phy.in_voltage1_rssi.int = 3 12 + +# and gain is low +test.ad9371-phy.in_voltage0_hardwaregain.double = 15.0 29.0 +test.ad9371-phy.in_voltage0_hardwaregain.double = 15.0 29.0 + + + +[IIO Oscilloscope - Capture Window1] +cycle = 1000 +capture_started = 1 +cycle = 3000 +save_png = ADRV9371_rx1_<i>.png +save_markers = markers.log + +#look at the markers - Fundamental +test.marker.0 = -12.0 -4.0 +# DC +test.marker.1 = -100.0 -60.0 +# 2st Harmonic +test.marker.2 = -110.0 -75.0 +# 3nd Harmonic +test.marker.3 = -110.0 -75.0 +# 4th Harmonic +test.marker.4 = -110.0 -75.0 +# 4th Harmonic +test.marker.5 = -110.0 -65.0 + +capture_started = 0 +cycle = 1000 + +axi-ad9371-rx-hpc.voltage0_i.enabled=0 +axi-ad9371-rx-hpc.voltage0_q.enabled=0 +axi-ad9371-rx-hpc.voltage1_i.enabled=1 +axi-ad9371-rx-hpc.voltage1_q.enabled=1 + +cycle = 1000 +capture_started = 1 +cycle = 3000 +save_png = ADRV9371_rx2_<i>.png +save_markers = markers.log + +#look at the markers - Fundamental +test.marker.0 = -12.0 -4.0 +# DC +test.marker.1 = -100.0 -60.0 +# 2st Harmonic +test.marker.2 = -110.0 -75.0 +# 3nd Harmonic +test.marker.3 = -110.0 -75.0 +# 4th Harmonic +test.marker.4 = -110.0 -75.0 +# 4th Harmonic +test.marker.5 = -110.0 -65.0 + +</SEQ> + +[IIO Oscilloscope - Capture Window1] +capture_started = 0 +test.message = Please ensure:\n • ORX1 <-> Tx1\n • ORX22 <-> Tx2 + +axi-ad9371-rx-hpc.expanded=1 +axi-ad9371-rx-hpc.active=0 +axi-ad9371-rx-hpc.voltage0_i.enabled=0 +axi-ad9371-rx-hpc.voltage0_q.enabled=0 +axi-ad9371-rx-hpc.voltage1_i.enabled=0 +axi-ad9371-rx-hpc.voltage1_q.enabled=0 + +axi-ad9371-rx-obs-hpc.expanded=1 +axi-ad9371-rx-obs-hpc.active=1 +axi-ad9371-rx-obs-hpc.voltage0_i.enabled=1 +axi-ad9371-rx-obs-hpc.voltage0_q.enabled=1 +cycle = 1000 + +# test observer path at 1GHz to 5 GHz +# SEQ FIRST INCREMENT LAST +<SEQ> i 1000000000 1000000000 5000000000 + +[AD9371] +# set Tx and Rx to be the same +ad9371-phy.out_altvoltage1_TX_LO_frequency = <i> +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = {{<i>} + {1000000}} +ad9371-phy.out_altvoltage0_RX_LO_frequency = <i> +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +ad9371-phy.out_voltage0_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage1_hardwaregain = -10.000000 dB +ad9371-phy.in_voltage2_rf_port_select = ORX1_TX_LO +ad9371-phy.in_voltage2_gain_control_mode = manual +ad9371-phy.in_voltage2_hardwaregain = 18.000000 dB + +[IIO Oscilloscope - Capture Window1] +capture_started = 1 +cycle = 3000 +save_png = ADRV9371_ob1_<i>.png +save_markers = markers.log + +#look at the markers - Fundamental +test.marker.0 = -15.0 -5.0 +# DC +test.marker.1 = -100.0 -75.0 +# 2st Harmonic +test.marker.2 = -110.0 -75.0 +# 3nd Harmonic +test.marker.3 = -110.0 -75.0 +# 4th Harmonic +test.marker.4 = -110.0 -75.0 +# 4th Harmonic +test.marker.5 = -110.0 -65.0 + +[AD9371] + +ad9371-phy.in_voltage2_rf_port_select = ORX2_TX_LO + + +[IIO Oscilloscope - Capture Window1] +cycle = 1000 +capture_started = 1 +cycle = 3000 +save_png = ADRV9371_ob2_<i>.png +save_markers = markers.log + +#look at the markers - Fundamental +test.marker.0 = -15.0 -4.0 +# DC +test.marker.1 = -100.0 -75.0 +# 2st Harmonic +test.marker.2 = -110.0 -75.0 +# 3nd Harmonic +test.marker.3 = -110.0 -75.0 +# 4th Harmonic +test.marker.4 = -110.0 -75.0 +# 4th Harmonic +test.marker.5 = -110.0 -65.0 + +</SEQ> + +[IIO Oscilloscope - Capture Window1] +test.message = All tests passed - Ship it +quit = 1 diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile1-osc.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile1-osc.ini new file mode 100644 index 0000000000..4282cfffdd --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile1-osc.ini @@ -0,0 +1,85 @@ +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = OFF +ad9371-phy.in_voltage2_hardwaregain = -156.000000 dB +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage0_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.out_voltage1_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2685000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2565000000 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage0_gain_control_mode = automatic +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = automatic +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2565000000 +ad9371-phy.calibrate_rx_qec_en = 0 +ad9371-phy.calibrate_tx_lol_en = 0 +ad9371-phy.calibrate_vswr_en = 0 +ad9371-phy.calibrate_tx_qec_en = 0 +ad9371-phy.calibrate_clgc_en = 0 +ad9371-phy.ensm_mode = radio_on +ad9371-phy.calibrate_tx_lol_ext_en = 0 +ad9371-phy.calibrate_dpd_en = 0 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +load_myk_profile_file = /targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +dac_buf_filename = /usr/local/lib/osc/waveforms/LTE20.mat +tx_channel_0 = 1 +tx_channel_1 = 1 +tx_channel_2 = 0 +tx_channel_3 = 0 +global_settings_show = 1 +tx_show = 1 +rx_show = 1 +obs_show = 1 +fpga_show = 1 + +[ADRV9371_ZC706] +debug_mode = 0 +interpolation_decimation_factor = 2 diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt new file mode 100644 index 0000000000..ac20ab2663 --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt @@ -0,0 +1,285 @@ +<profile AD9371 version=0 name=Rx 20, IQrate 30.720> + <clocks> + <deviceClock_kHz=122880> + <clkPllVcoFreq_kHz=9830400> + <clkPllVcoDiv=2> + <clkPllHsDiv=4> + </clocks> + + <rx> + <adcDiv=1> + <rxFirDecimation=4> + <rxDec5Decimation=5> + <enHighRejDec5=1> + <rhb1Decimation=2> + <iqRate_kHz=30720> + <rfBandwidth_Hz=20000000> + <rxBbf3dBCorner_kHz=20000> + + <filter FIR gain=-6 num=72> + 0 + 2 + 4 + 3 + -4 + -14 + -21 + -12 + 17 + 56 + 73 + 39 + -53 + -159 + -198 + -101 + 129 + 377 + 457 + 229 + -274 + -793 + -951 + -482 + 527 + 1564 + 1899 + 1011 + -978 + -3154 + -4109 + -2611 + 1669 + 7795 + 13807 + 17524 + 17524 + 13807 + 7795 + 1669 + -2611 + -4109 + -3154 + -978 + 1011 + 1899 + 1564 + 527 + -482 + -951 + -793 + -274 + 229 + 457 + 377 + 129 + -101 + -198 + -159 + -53 + 39 + 73 + 56 + 17 + -12 + -21 + -14 + -4 + 3 + 4 + 2 + 0 + </filter> + + <adc-profile num=16> + 599 + 357 + 201 + 98 + 1280 + 112 + 1505 + 53 + 1331 + 21 + 820 + 40 + 48 + 40 + 23 + 191 + </adc-profile> + </rx> + + <obs> + <adcDiv=1> + <rxFirDecimation=2> + <rxDec5Decimation=5> + <enHighRejDec5=1> + <rhb1Decimation=2> + <iqRate_kHz=61440> + <rfBandwidth_Hz=50000000> + <rxBbf3dBCorner_kHz=25000> + + <filter FIR gain=0 num=72> + 0 + -1 + 1 + 2 + -2 + -6 + 6 + 12 + -13 + -24 + 25 + 43 + -45 + -73 + 77 + 118 + -124 + -183 + 193 + 274 + -289 + -402 + 423 + 579 + -607 + -826 + 866 + 1187 + -1244 + -1759 + 1842 + 2818 + -2970 + -5815 + 4337 + 18436 + 18436 + 4337 + -5815 + -2970 + 2818 + 1842 + -1759 + -1244 + 1187 + 866 + -826 + -607 + 579 + 423 + -402 + -289 + 274 + 193 + -183 + -124 + 118 + 77 + -73 + -45 + 43 + 25 + -24 + -13 + 12 + 6 + -6 + -2 + 2 + 1 + -1 + 0 + </filter> + + <adc-profile num=16> + 596 + 358 + 201 + 98 + 1280 + 134 + 1509 + 64 + 1329 + 25 + 818 + 39 + 48 + 40 + 23 + 190 + </adc-profile> + + <lpbk-adc-profile num=16> + 599 + 357 + 201 + 98 + 1280 + 112 + 1505 + 53 + 1331 + 21 + 820 + 40 + 48 + 40 + 23 + 191 + </lpbk-adc-profile> + </obs> + + <tx> + <dacDiv=2.5> + <txFirInterpolation=2> + <thb1Interpolation=2> + <thb2Interpolation=2> + <txInputHbInterpolation=1> + <iqRate_kHz=61440> + <primarySigBandwidth_Hz=20000000> + <rfBandwidth_Hz=50000000> + <txDac3dBCorner_kHz=92000> + <txBbf3dBCorner_kHz=25000> + + <filter FIR gain=0 num=32> + -118 + -122 + 242 + 240 + -429 + -499 + 730 + 900 + -1154 + -1615 + 1742 + 2957 + -2322 + -5354 + 3885 + 17211 + 17211 + 3885 + -5354 + -2322 + 2957 + 1742 + -1615 + -1154 + 900 + 730 + -499 + -429 + 240 + 242 + -122 + -118 + </filter> + </tx> +</profile> diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706.ini new file mode 100644 index 0000000000..34a98d4a77 --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706.ini @@ -0,0 +1,89 @@ +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = OFF +ad9371-phy.in_voltage2_hardwaregain = -156.000000 dB +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage0_hardwaregain = 0.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.out_voltage1_hardwaregain = 0.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2560000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2680000000 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage0_gain_control_mode = manual +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_hardwaregain = 25.000000 dB +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_hardwaregain = 25.000000 dB +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = manual +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2680000000 +ad9371-phy.calibrate_rx_qec_en = 0 +ad9371-phy.calibrate_tx_lol_en = 0 +ad9371-phy.calibrate_vswr_en = 0 +ad9371-phy.calibrate_tx_qec_en = 0 +ad9371-phy.calibrate_clgc_en = 0 +ad9371-phy.ensm_mode = radio_on +ad9371-phy.calibrate_tx_lol_ext_en = 0 +ad9371-phy.calibrate_dpd_en = 0 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +load_myk_profile_file = /targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile20MHz.txt +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +dac_buf_filename = /usr/local/lib/osc/waveforms/LTE20.mat +tx_channel_0 = 1 +tx_channel_1 = 1 +tx_channel_2 = 0 +tx_channel_3 = 0 +global_settings_show = 1 +tx_show = 1 +rx_show = 1 +obs_show = 1 +fpga_show = 1 + +[ADRV9371_ZC706] +# NO_DEBUG=0; DEBUG=1 +debug_mode = 0 +# 20MHz 40MHz 80MHz=1; 10MHz=2; 5MHz=4 +interpolation_decimation_factor = 1 +# is taken into account only if "ad9371-phy.in_voltage0_gain_control_mode = manual" +rx_gain_offset = 69 diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini new file mode 100644 index 0000000000..e12de4edbe --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini @@ -0,0 +1,89 @@ +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = OFF +ad9371-phy.in_voltage2_hardwaregain = -156.000000 dB +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage0_hardwaregain = 0.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.out_voltage1_hardwaregain = 0.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2560000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2680000000 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage0_gain_control_mode = manual +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_hardwaregain = 15.000000 dB +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_hardwaregain = 15.000000 dB +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = manual +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2680000000 +ad9371-phy.calibrate_rx_qec_en = 0 +ad9371-phy.calibrate_tx_lol_en = 0 +ad9371-phy.calibrate_vswr_en = 0 +ad9371-phy.calibrate_tx_qec_en = 0 +ad9371-phy.calibrate_clgc_en = 0 +ad9371-phy.ensm_mode = radio_on +ad9371-phy.calibrate_tx_lol_ext_en = 0 +ad9371-phy.calibrate_dpd_en = 0 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +load_myk_profile_file = /targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile20MHz.txt +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +dac_buf_filename = /usr/local/lib/osc/waveforms/LTE20.mat +tx_channel_0 = 1 +tx_channel_1 = 1 +tx_channel_2 = 0 +tx_channel_3 = 0 +global_settings_show = 1 +tx_show = 1 +rx_show = 1 +obs_show = 1 +fpga_show = 1 + +[ADRV9371_ZC706] +# NO_DEBUG=0; DEBUG=1 +debug_mode = 0 +# 20MHz 40MHz 80MHz=1; 10MHz=2; 5MHz=4 +interpolation_decimation_factor = 1 +# is taken into account only if "ad9371-phy.in_voltage0_gain_control_mode = manual" +rx_gain_offset = 30 diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB25.adrv9371-zc706.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB25.adrv9371-zc706.ini new file mode 100644 index 0000000000..bcdbf7716a --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB25.adrv9371-zc706.ini @@ -0,0 +1,85 @@ +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = OFF +ad9371-phy.in_voltage2_hardwaregain = -156.000000 dB +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage0_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.out_voltage1_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2535000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2655000000 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage0_gain_control_mode = automatic +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = automatic +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2655000000 +ad9371-phy.calibrate_rx_qec_en = 0 +ad9371-phy.calibrate_tx_lol_en = 0 +ad9371-phy.calibrate_vswr_en = 0 +ad9371-phy.calibrate_tx_qec_en = 0 +ad9371-phy.calibrate_clgc_en = 0 +ad9371-phy.ensm_mode = radio_on +ad9371-phy.calibrate_tx_lol_ext_en = 0 +ad9371-phy.calibrate_dpd_en = 0 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +load_myk_profile_file = /targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +dac_buf_filename = /usr/local/lib/osc/waveforms/LTE20.mat +tx_channel_0 = 1 +tx_channel_1 = 1 +tx_channel_2 = 0 +tx_channel_3 = 0 +global_settings_show = 1 +tx_show = 1 +rx_show = 1 +obs_show = 1 +fpga_show = 1 + +[ADRV9371_ZC706] +debug_mode = 0 +interpolation_decimation_factor = 4 diff --git a/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB50.adrv9371-zc706.ini b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB50.adrv9371-zc706.ini new file mode 100644 index 0000000000..a23a765503 --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB50.adrv9371-zc706.ini @@ -0,0 +1,85 @@ +[AD9371] +ad9371-phy.in_voltage2_rf_port_select = OFF +ad9371-phy.in_voltage2_hardwaregain = -156.000000 dB +ad9371-phy.in_voltage2_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_voltage0_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage0_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage0_quadrature_tracking_en = 1 +ad9371-phy.out_voltage1_hardwaregain = -10.000000 dB +ad9371-phy.out_voltage1_lo_leakage_tracking_en = 0 +ad9371-phy.out_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage1_TX_LO_frequency = 2535000000 +ad9371-phy.out_altvoltage2_RX_SN_LO_frequency = 2655000000 +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage0_gain_control_mode = automatic +ad9371-phy.in_voltage0_quadrature_tracking_en = 1 +ad9371-phy.in_voltage0_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage0_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.in_voltage1_quadrature_tracking_en = 1 +ad9371-phy.in_voltage1_hardwaregain = 30.000000 dB +ad9371-phy.in_voltage1_temp_comp_gain = 0.00 dB +ad9371-phy.in_voltage1_gain_control_mode = automatic +ad9371-phy.in_voltage_rf_port_select_available = OFF INTERNALCALS OBS_SNIFFER SN_A SN_B SN_C ORX1_TX_LO ORX2_TX_LO ORX1_SN_LO ORX2_SN_LO +ad9371-phy.out_altvoltage0_RX_LO_frequency = 2655000000 +ad9371-phy.calibrate_rx_qec_en = 0 +ad9371-phy.calibrate_tx_lol_en = 0 +ad9371-phy.calibrate_vswr_en = 0 +ad9371-phy.calibrate_tx_qec_en = 0 +ad9371-phy.calibrate_clgc_en = 0 +ad9371-phy.ensm_mode = radio_on +ad9371-phy.calibrate_tx_lol_ext_en = 0 +ad9371-phy.calibrate_dpd_en = 0 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage0_TX1_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage5_TX2_I_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage4_TX2_I_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_frequency = 7999809 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage6_TX2_Q_F1_scale = 0.251160 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage3_TX1_Q_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_scale = 0.000000 +axi-ad9371-tx-hpc.out_altvoltage7_TX2_Q_F2_frequency = 1000327 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_phase = 0 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_scale = 0.501160 +axi-ad9371-tx-hpc.out_altvoltage2_TX1_Q_F1_frequency = 1999718 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_frequency = 19998117 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_raw = 1 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_phase = 90000 +axi-ad9371-tx-hpc.out_altvoltage1_TX1_I_F2_scale = 0.000000 +load_myk_profile_file = /targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/profile_rx30_Tx60_syr.txt +dds_mode_tx1 = 1 +dds_mode_tx2 = 1 +dac_buf_filename = /usr/local/lib/osc/waveforms/LTE20.mat +tx_channel_0 = 1 +tx_channel_1 = 1 +tx_channel_2 = 0 +tx_channel_3 = 0 +global_settings_show = 1 +tx_show = 1 +rx_show = 1 +obs_show = 1 +fpga_show = 1 + +[ADRV9371_ZC706] +debug_mode = 0 +interpolation_decimation_factor = 2 diff --git a/targets/ARCH/ADRV9371_ZC706/readme.txt b/targets/ARCH/ADRV9371_ZC706/readme.txt new file mode 100644 index 0000000000..05b3bc1b7d --- /dev/null +++ b/targets/ARCH/ADRV9371_ZC706/readme.txt @@ -0,0 +1,17 @@ +Common command line: +-------------------- +cd /openairinterface5g/ +source oaienv + +HWLAT application: +------------------ +./cmake_targets/build_oai -c -C -w ADRV9371_ZC706 --HWLAT +./cmake_targets/lte-hwlat/build/lte-hwlat + +LTE-SOFTMODEM application: +-------------------------- +./cmake_targets/build_oai -c --eNB --UE --noS1 -w ADRV9371_ZC706 +sudo su +source oaienv +source ./targets/bin/init_nas_nos1 UE +./cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1 -U -C 2680000000 -r100 --ue-scan-carrier --ue-txgain 0 --ue-rxgain 5 -S -A 6 --ue-max-power -25 --phy-test -g 7 --rf-config-file ./targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini diff --git a/targets/ARCH/ADRV9371_ZC706/slib/libadrv9371_zc706.so b/targets/ARCH/ADRV9371_ZC706/slib/libadrv9371_zc706.so new file mode 100755 index 0000000000000000000000000000000000000000..c060bfdc57da7c5213e7b6f4c6b576f28a9cff08 GIT binary patch literal 260713 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
#cavERYdaM4 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�nwUPTBg}V|DW==6CsH_=v+?80m|_2rNYS`5 z#Z0?q(}YsGSEe}M?wCk%wW09m{ukM!5-GNyul2~)e=N1!UX(~-&C*%Erq|gwB~tV> z6#1Tv8|^0(DP|jrRFC2&`xBo+rqSyvQ_Qy|epuEid_fPJ#Mn#s7^=2P3sM_e!MXH< zpd{luEyewlZMwf2t{o{`9BGL3{@OOXzZyPN8oW-tS^s8)V|<s7s%u{Y$JA<cFGFt$ zV<OGZ9>#|HHV=Pne-+Z(-@vbx_!`EnQ+eyeX$&SW8-~MVSZXSyUE~y#<&Pt+?W6J1 z$h_Q8<N{U&wu_o-3B8%S-sBErZWGT~g?w*UT|!$~v-xFNgY_Q-iw0<*zH*P#rO(7H zYwD$5d|bu&cneS+A1@=SR(bL93QFq&RN`ZEBX&8<z4{|4bzFSxV@Uo~e2g06a}n&q zP_XLw*w|1>eDqY%@o_GD>Pym$!wl7oh_18Ru)L!eA72*txCqtI@$nULkTsWk@$fZq zkr7t_e-PfK_RGcH>8oMDsVw1jn@>jhO2%M0H~S5nOA)(b>$1TgGPb;F@a@Y6k7V#U zVDJZ*4KHPMdduEUrCMEu)unn{)V&+RTdij1JAx0o68J;RKPdP+#QVW1)VqRjy9)TI z+Q8ov{N}5H?_=Tb3tq7X_$(Iwf#4l0fb(7r^`YR~ftSoa+fpA1T67Jv<wdx^3Vsjq ze^8x$VK({o*J6=ESF_5fIeyOptp063TwolrLl=|bkL_PPuPME0o5}aXPfGY#Fw6Yp z7^HWYWe5^IW!OszQamC*c+?1YZtkhDxUvfK6PeeWe4jZZJlAKwtuk}w3tq`m@dr)* z$E<km@HU_EwaSd~N3}9S{MF>gLrM5&FiXWN)}rFS8G^)$Z#KGj#1o%lW5X0I#`*C@ z)erY+VMGmB2T}QkAW_ubDnu0<N<ZW@2w&leQrAIL-zr7r`9_ht4XrFCH~hLM<xxtR zRHc-zz7#R--Z{Eju?(1YSU97lsnP}4LqgJAotapr!=_5cFxML*zh%dUhe3*j$PTxf zOy4uF^NW{CJXx7}O882j`K8Lt`xBYHe81$W;TL`8cPcaIzN{-_)E+!fqdxPTaJ5#R z+NCDbS9_Sx+?_xAc=^L<wRz!>z}RUJ;DYr4P6zM_ft~<1-hjb~WFscv>uF#Ty>D8e zOJ9yeHDd$$IlEnYBdq?o$xF0)a9X<z(fKqy8uZQ4d4^H=+Ri8h()6Q4lh4^LUtw!~ zoslfj+fzZJw+=8%jg;-wYEd}1(5Q7c)!JY(6V-ZfZ-P~8%-3iwld5hFPw}Mm{R^Zt zHUx=Mk`kqOMA@E{+rnEtDR)y!*D9qnNR;9cA(F~R-5x&TNr`TNl+&w}(kW4jN96m- zmT*y#=O+`51m92A`+g$seWS_unI8yG_nGgg%zSEM$!}F=el2{L&-_Vc<|#h2^y`0{ z{Eyj`pM*d487CPZh^y=~ipu3C-&graxB+6I?#|0AGsj*r#?=mV?m~^q>x`e;r9R^V zli`=T`Nagr<tD#pCe*DKuJ9QvDl-=Q(MRgJ+2qe6<KMzB`iwg&GamArMi?J9`J2gj z$hKR1b$p>R<NicdUpD#s$ruZl_>3P`X8g?`g{4G3PL&UaVRd$Rj?ef*WyW28#}>w) zOnxyLM~Cn88D%LBk-k-z`;5|-jTY$w>*znYzcPFj%o1v5vj>zIg2djqC(%+T8KUtl z{y?}@8_!awnGC=9g^8{-&E#i$#j9``n5FoQEPiE`#aoFjyvh)*Vey;7k3oVr(=~c- z>aep)LG%53biQM@*5QH9I1UgJFuP4k<)zIClz5xIb&oQg|0?oZ4>!nrKssMxkY9k* zY-=Lx`ln5mI&U@E`~|R;WXmsroxPbytuBcFnhihS@R`I?e4mDCMQ3kDaS}+%3@b@^ zXCMec(%PFTi~&h&Z@`}or1P9|t-&fFcWe2o9mOxB&VkH*Iumzw)bO%zGud0f`)NGe z>ikfEPqmY}2KinM@bQ`rsLE`s^H+h45-%gf@{&>qT0Nmrc#c+=MUL?(Y*Ii%PpflH zlh5ib^76yJ#)X0G8@=o#KYK_Z`%y1D+0ULD$bQ$$t|o<J*<f|9W2OpwQMlb+oC9W* zA=G>042rVJ+5{+DotUz<)wy4Q@{B}E?`<?Ab6kM(!bHl`;{!OHwDY_G<vod%6B8*f zH<WbR7ljf}3uk)4q4WKL?617+Eq?a5fpRiBXnW8lA>-3PIk1PErh=BG<+>$OewRpD z&&(c3d5)nJXOGxH8>5!(1C$ksltIgZ@?=AK2r{=BO8$mBf`?eNo@GYBP*)&JgUIS2 z;tkOx>-@0E$poT0dLAA&E%lPgZHL_2lB<91|C>o4z>>UycLe24U!dKdcTfy69AzNN zSftZsBIZSDPQ+S|3FdeKRHkSn`Ho^_3twp($#)bZcL~_8HdJkXGlZW$&&A<yvXE@~ zIOIp{%|~;koHOKX6_dEeOPpE<oUJtFcrS55O(eEEL)eQ=VyW!sI-Q9O_4T+Z%o>%8 zuUh`uU)*<5?>i(}XTFk+*C!^2xvQccw?<lLK9GZyf7;wyQIAiAturUqMal%l{T20O zljrDT;7S{OJ`+TKDG%(5$bnsqt@XI6&no3rYuUA_3Aa}0ZN;S(FhQm~J-*LpAG0nC ziDO7vIt+zHju7OpUs}>x-1)U0NgVq0zG!asswd_z#cat6$+32PdaCyvvvN(XvA@>B zWAT^e_f9@au6HGpt+7u+g)F_=FJY>Dk)s|Ta$ze~FQi7e<!}t&9If4kFPM$BGO_df zCV5?tk6ol3Yitbdl66VwC-ALes(gtoenHk%l*OHlWB*zkq-*7=0Y|n#vD{E*jopd- zoCAvW<j7X<QvmX1ja!U*WEChHf9!2|(2})Hbw%!BlJN`W{1bm7+&np!Z-{0+qxiIn z1DX)%)*kyP<xCTMboH|YlCSNM1W^<{x`>T_lw(=FN(5tn#WU!v#flZ=@TN5w`(+)Z zUM#7r;;A>mMY9UzII=BFrB?O$5U3uvt5{>pYa_pb<nK+)Cy_Pw1DGZ&D?~>;#QeB@ zxmngK<<)xGIdm7sgupiRGbd2;_co)0_T#ZTsLNSlx;dkQmL*o!vUn+Bb{1tZIB0(z zb3IH}x0GH!`W8q`o5S#+y?%UtHr)11GSuVm0(eja31RC2e4E#9ABPorZrPqi%*HPR zhz0zl<Urv+eNvfsw3(CiFUSf<AtW4s?KT{I?Ka6tb}mN&=2hBo5?nXQyd`@J(yKAk z>5kNc$;a~WC-M*ylJ)zrk(bf3$-i7gk_g_WvXXx#9E)^CiOIha&W@}n&A$of$`NMC zzZ3RP9V6nOI!44lb&QCA>KGCK)G;FdsbfU^Q^&?ZL;uvV$w2&5$7uCgDQ&4(@O@aE zIyM<O{;6Y_LBvlT8vw*Vb!-}>`KOL80^*-KHVb6_sbedE_@|B$@lPEi;-5N3#6NYc z0*HU=7!~zT9lJ2(zYm*yqtgeb%ue3SN=8cHoXIy6v?87GoqP+c>qOcTzJo&eK5QW| zIeRXZ4N0}l*4t!<ttqJ$UTTIFd=s{sya{XG<`lwR9$^CrT@NJ87dV~x3!F~JUMMA` zLVWGToU`X_!j6R7BC|R{`N$zg>)F)KisB8<NEuVZk#9f}DJPsAISu_hGN(V_mXYC1 zpUd>ck;}<CkMJ5x&Ko3&R3@yeG1kW=6`O`xa%92hRFp3RrgSI=Ng6?%xdt%C1GPef zS3nz^Ka{0&hp@)eZ(&6SQ`2<r5DpDyBUv$SIJT!S*?yHA+;D79*#O+NGTudbYA!Rq z{<{t^KWf8kAk5^xYc-c=XT1oPOm4l_^!80aH=u@U?jDp@LR3y!6ZA5oZCiP{Zv(CQ z4BB7KzniL6^sFU6vn*iAjW;4_Ekg<KnGmv{go`dh@!7W{IX9bc^;)(0!tZF%;$^4B z_{L``lzR$fIr_)b94r8SP$P1%?5OCOgH=tZ96mA4;W=eFp?Q{_a#Z2WC&Ro0%vMHH zJ(P77)fjKm|4PaDs11i<Yi)q5Xn-v!TN^;=t8D@*2Dpj_m_k$xa25F;1gdMihBdY; zHZRjvu3%Xin@yFMn?f;l!3jL`z<6Ah$AZ?X^G=}3_k#>o#t+4)F@98Lg%{(y>I&ES z*|0v03V-^CtlB_5mY_g<#6UQ~6Y6K&S{M3lqv}0PE=B<P;O6yY&rI8Brn@(LhS>HJ zSU)2wo*-!5n=zC~+wY*XW%b3Q?k8;37i&Ji0<8vXS>l6)M}non5uy(fy%}ikP@@Gs zI^OzhYb=al3GD}^@+-QPk;_Jw*f7lSjbVBCs127?^R$1K+J6V>x*4BkPUl-N#SnF$ zr-~N?)f&Gb8aEJ)_foC>$g24(wcJM(XS>yWp2fbXu`zWPnxfgQc+{ESf^n^RAY8+1 z0(6yVTBBy63h18f(6kv{SilF=WV>M+$4cR&HjG8g(9Zh->*d_))$0S+YXneTuaC&S z8K|z;Ujy~}n5ut+EM2cp66*D-SFaBP`gTU4m2_?+I-_340(6yV+IscMxRf<IN*!WL zSr6P@r2n8syeCiB=qPK{_%^RbM_Hruf$AE`NWUAXuF;Qy8vR72lW+HG^sj^({p{7K zn<<(tRUL&^(zcyfqmco+N;K`g8Z|nLH8O`=7<z<7`KS%ALwaKgv8jr6>JHT!OAtv_ z9J=NKZzAp&l_~8rz?({sNfX>^Dh?P^R6X2G+%H{moC{S<Z&;D2A3DQG1PtwNx)Rgz zPRe~$Fh|5~HVko_-;?4gm?H}Q;wzY=X!U+~cna1N3D*MG3f9*O=81w0M8S`csdda1 z9PZvs`ba~Aj;ZrXK;=tNb|tfR@J#<jfUXivN8j|E*s8XoH#SkrXBbSwkJ@l9qG6tx zzP(V?x)aK+pe;Hmj>~q%_N7g*!K0(pV-9kgVE9*^1Rb&k^FfZkb&Xt<Bp+Ng%(D(^ zKZU$)AZpmg5d0OzK~W4ud~UJ*6+^G3>@!4|>1!zi)s>J^Kq(F1GMPVX2@(5XBD0r| zd5vZsq~7#Yc%Ld9u2O{tuNr!-f=ATElQLK}gE~@?YIi|O=5n2rSdk7!3Tz&k8*102 z%xcsaY+@Ua!&hvGn(m2gOOZuYitL}Lm`7CKQ*5ZZ-;*+qQifD1WkRBqsfMV5C*>^l zZ%@h<l(M)=DVAS7ecGqgtJ8&A2>9irN>o?0jc%=zO{U*ktNhlglW7_vBWhX0!J!@3 zYB+wm7Q~Kk(yZouyi$D&XUNU@c%}MX1Y5iY2Td8xh{n;mC1XZQVl7wjOQ84{XUSHp z_dwX97Wrl{i|tn>pHR2pqXvC~K5L*QZa|uA73Shks{e$Am1xNvtHpc@FQIVWKGc$5 z7@^pSik4$QOzG#VX<4r~N1(F$Va9CMj~mdiTt5yohO36jA3xh6w9>iPdU5#Y7nNoi z*%i{{^rrAd1cRqHg|A?WIkG9dRVaA`c6b}XWaoa;2ajw@n*R}!<jAI^g_i-;M>Zub zx|yIpvMKohO_A*U1K$x!kRzL_eQ+H?9@*p+r=Y_6$fn4#%bD^JX#)piM}FCg6n$h< z<X6J_$fn3|g!Pe4k$)4`M>a)%C#;vK5nMtHL@!YzN)Ww7jf4czOVmhM5WPf=BnhII zsF7qr^b$4VsHdT!UZO@))LtNZi5dwWj2#Icj2#Icj2)?^20$HsFm@zMjRm5YsF7^- zDx~QpYNW3E2#8*yMuG=pM}h}qM}h}qM}h}qM}h}qN7^VhlwP7nf(K(qIw&r$%#lqI zb7WIwGb<@aHbrhGsE=%l+`{VWBby@r!Px96IItRRn9Am*+BH@HU@BWvQh7+3q{f%1 zr=`Ky2GMKe+@_RgxpbFvn^K-Lo~ciRN=Da7c8c&FO)H;abxOK;4`62<x=PZeWU`!c z!mG4^W9TYLml1ZHl}wk@NK>5<qFvGzOpiJ3asjU<oaszw`jv#UopQog5w7brAn(<L zbDa;FehszCcVfAKul)*eu_ebMRWI%ZB>WUQdiB<9T(f?zRtgE(sY}qqtr$kj)Me}m zRt(1-r7nLIkU8!sbp;O_PS?jBrCxj$;+q_Il)8#U`naRi%Lwb^j#956tdBcNT}@aY zca(Z1VSU_D>eYnxaYv~Yg!OSpsn-zJ#~r0!OIROwl)9F%KJF-W9btXkQR?;7Ss!<l zx}LB;?kM#J!uq(QRC%3LA9s|xf$93Vqtu&Nm4hy)0I8dpesH|Y<Bn1{6Zv?&%j1qx zZzghRyn72GZ0fB<4v%+v+)?W7)Z?e|uAK$sP9n|(m&YBYZXuFA!97H>t#x6({0T0P zJ4(HmNbv;sRwDNi=`_LRaYw1!i1eJ`^0=ea?L_)daQ9&apSptxk2_*ZZGz4j^k46| zqtpkgBRRc3l-T=p>O;raJUs3w^%1h^<Bn2yQg40SQR*)Gj6Uut^)ZUec6r=U>f?mH z<Bn3Fyc?K2)~L~;dNLf*Kkg{nHXVZHxT9#NX2_~3#~no@suSjzDVO5WWVAYe0R%E0 z=8Q%K38%~;lCGWsl|Jq$nyLN)L?3q)%~Cu;MIUz*t)rgDgi;@O6s@OT2BMEUisq`d zkgSh8isq>=k)w}0iWaJ5G^IZ7DB50-o^sq#w1?_~9DUqTbg-HVL?3q)Jxv7Y<Bp=G zg6QLpqGzdvAk)VkMJGs(KJF+wP2GSTecVxWwt4`FKJF+wU+n|3%BmHPo-`aa%aY@c zvgEj<EWR2avclcqN73Fi6{z}`kxGs`$_gBJ6dgEL=buhvWyx_zS#sP_mK=AKCC43Q z$#F+na@<kYMUbAHCC43Q$#F+nf#Z&%=PlLp&ZoVz<hY|OIqoP+jyuYF5=!CttW0Ph zo%gDyUBu?dlH-oD<hY|OIqoPcaNJRJC6&&OMKA3KS~>10dRZ&Byu9iky@Ieg?kKvN zM>wI*SI?kaIqoP+jyuW<9CsAG?lk1qUaq1y9E*Tgyy-9EOwJXl(C#L}VP^p0O|+gq z?kIXQ(^H*aY290g0ggFy5W%CjQw4q8QS?sI<T}Ol(7OmXafY~n?;)J;Tn|@@-b=Wp zlMKnxZG?-R!KB|ob@XvZ(FX|Y<Bp;aCxJ^JcNBe;us-f6`dCfC`naR$lR1F(aYxao zNu!TDiatm9u*>6)qAw7RDVN6`MfXwZV&(F<qv%USIw_aO9YtTE@p>xvGq%)gEx>cK za(UcQ^bIOILb;PE?M))3%H?rK(YH9k7_VF&cN9HH+nlRh9(NRdkD_NOm&YANKOn;6 zjvAwTQyUo&aoiEpSsQ~VJ8bM!`Zvq>s90jxI4;K>ML*(AEZN1;uXZCxjysBeO>OjX zN6~LzLQ(p-qv+oW>*J21he@N4JBl7*x<2kGdX%s}?kM_C(&*!kqCauO)yEx0e<o~> zJBt3&7v<s?B>AQe+<IVr0w9N9$jX6*k{ul6tg{$FBr9hvvU85&3)$a!+3o!782EAo zrNkWn3)JLHcG$6`w6lF4ff9K@NJ+^~Pf*om#PJk6-{WVn(JC<{N=cw!?qxIl#IupJ z2?=!>hqO}E2C0uCK_7RNmR6Dqt3QT>v=~8s+)-M(B*%E%QCbGuJQm||M`@Xa^>IgO zH3{qEj?%K|N%_t|%Bjt%l|Jq$tqvQ2#~pDHl;e)la$W;bx<2kGt=<(iP^5zYr8S^9 zecVx6E@6G#QCdU7`naRC#)S28M`=w6>*J2nniAH>9i`<F*2f*C<rCJ&9i<fz*2f*C zH7Bf(J4$OoSRZ$k){3w`?kKI8us-f6tu<kN+)-K^!uq(QG`YTOz8tWa)`7$7ayeiz zts~)8a=>C*C&FvwfW@>fgxAXfi)mds<Jc@Sj<jw}->hdGY2Arz(KC*;9z?e58AsYl zM0Sq1!dIe?ru7<v_DXgvahczdQ|%N?{bH)&3pMaZPTy}tT`lK|+ITq9m`#NEYv%%K z!Wm3G{v=@!rc>BqjK}rm&=SGx-@?Sf^yK>dNx~ld5kRY67Ze%l#$>xAI2w!_R|b45 zaDX!blB~X*jMD8ZfVoyZeQb)bj9?*>ImKkY1&u@FBy%w{Z-qvoal9lz(~Z+~4Zj4P zI;eQZasAr~zbjx#F2MJ8GnG?P^**O9je2GR{E!|8^U%TYt2y*;+=tXHc(a|iWWAX* z_^1s`ZPI{}TM~TaE<6pxGo(VQR_ks&U|NI;vMQoIhXT!G?LWDYya<2#51v@@TD1Ir z$SU~G<jpL=V*sB0vHVp-h4WiX-laMZ=jS)a!@Zu=lTFtmLN!jZII+X$O8o~qZufQU zMIGOU9xdgOV{fXZCQ#u%R5<M(e6@In8lSqxh*^t{$dB4^1d~c#)zc_uG>Dt9<Er88 ztk(i<c3v*fk!;qNfwsDj3Y|_qyW;TD!buYr_~`Owt$xCU(aT-4tWfTPFvOde6_(+} zWiNO8vQ`r*>Wp9LQrJn{Y%$T&P!<Lil-6|0EL_OI)*nj@)sZ#OS|H8NB&95ah~~Wk zqR&m$0Ln*Ad={f~(NDm4f~M#@07nRX3ZVJDpeZKX_lB()^-)uP^jOM3AT0L~Aj@X} zG|N%LGK(x{H^<m1rL?)vu$)JLEVlsAEdMkto5?ciERUu3Hp6l%0kT{MK(nZofbiK* zmdSiyQA+u{$I@)OVHpcRvxE&x3>H-9Jmaz4OG;M%3y-DV4zT30m!D=>ny@H*)Qsks zOcXUo)>;r1H2|=OKqi3C0Tj$N9Jd&MT?~&Nq1rabFE*{4<F_k7r4hU5n_8YJW}#t9 zHL2=?ktimg#pJVye2TY<sS#iJ<)<erQO0wZM4M_DM?{;p1W0}cfPx*Bv{_PF8zc2j zLpO_3=e+@`RTloVA=^x{1^HOzN#P5<!td}3f02cMU8(S;Cn)?wL${w&mz)Brl?#`) z_{EUrO8r5)>@H7%?>q%+KVWL#4M0K8MVi!Wi)F_vAd>4Fx-?Jn$^%s>A?9yuNG<Fb zQ5UyF@DvM-XSr;t)t&;|sX%F>0^y27OOq?PgK2;XhO(G)FMY$4`=%%NcTaAU2O;;# zM7j8J6jDP@56{a&PET>OEwAbtHCLmu?2<P%Qf5_rzI3fBF349_t&HZlu84sOe`DAy zi$B@e35!3u*o}!l`Jyzm<aqR|DOX;zT9b!Sr09Gk_k&JFlK?Oh6?|=o_IuI1uPK-{ zM;|y<m7pU)XCw3{L%*3-zqSGTvj{Eogl+=Ry79$Y`JW(kA<D%tp=&J?Bld7phShpl zfbzCKq~z<u{7~kre@J<Efbyq5qAYkPKzTwPb!@RN(Zx5>e=Id^CF<UWoj%3xVd}G~ zExpQa!yc{16f`hAo<}D}7X%iM4<_4Tf@*eiTxbc&P=~vlpEt>Ek^F#8*6*ntG#MOe z8C6M-=7L}Kv<keI9}X_RUJ<*uXLkKGkYkf9YeE>Fi*0Pr8j%aV{{pwL)M8}Tm$7pL z$IeDFZf;~&BN;O{am;Kl<E4O&WUSPwGcdPS8k8|o6Ug|und4(485?hA`BsOoIhMPM zLu0YA*EZ1bqc$WXv!iH{p{T~w@UBiAN^1(kFF-qsX0_z$a2E$6`xq(1I5n)L@-c=N zWh4FMhp=*EVo76QQ-O6W1i<dpt+N2jmvuW?fHljyog%>IW!=scVEeLelLgqhtb}3r zIk3w}z08yb_2r}PnTehuqg(W00353N6X1Zj9Dp9(RvWhERC3$R9?L$DMLl9zIs?!w zR~wc+WZ8PaV_8K?ma@lV`N?OgFf513a&I+!i()75G%Sk=P_YLA=u&PlEV<lNb6*#a z#eUSVbR|HRG60%ogJBs@mhCe<mZv?IpFNf~yTBqb{7b{)_ojyrkd3|RE)Yp@ev1Hm z(!T%{RKFCw_*C7OPB2oZ876<E-t{|*sXSiEP|?tkuBn4cJT?;FqD|f1Mw|WwsLgZ$ z1$`@NbE1*D#L(@b)IE#wU1i~C7_!48d-@Hp@T<MTcYB5Zm4z>^RQQQT>e+@aHwRLm z|5p`-OIuv&k!b^4YVU9`NbN(9nc5c;VC_!>P;hT01x_?lZ#Q)QNd59sNUqWX&l%ET z)b-W3Jq6}?3f$}|@EjHRI#Gc?7^#0Sl*=i1|Dw94Vuw7rnU9-_bp}u{bd|P&=VT`u zsSm!Y>Hfn=jSW!$X`q%C*lvo=_gdh=4?RW4P(KbTt2{-wQqk8cDf&kv%V5*jII<jt zTr;vvFv%QQYSfct8CeR-Oomy*`J)PUf^cc**{GJMY_=)~dlA=$uTi&2Mz@)I@Dcuq zJ<gw2==%%1i~xO^A>Gc_sjFV598OVwfgG8lFu)gFZK(VyiuIajemzC8Q${OJQWhh* zwI`Ef-}ew$)%aI%y%Bkt)={Q6Juc=tthf5u<gNEAxZx&_Lb5hLS=Q-!PhdvRQK*lM zLgRs+#Oi!$I9Gd|{Zt!PC&eDWUngynT0IGdg0jnW66Z6}k(<N3DObd&2T6wqsn!^U zAZjf)Jb9WG1LU_*t(UydaF*hOEj6;2yvQ(CV<URYJ+b43yZ)14JDCq7wi`L^Fr@OM zHXO@^#aAI~EQs1{1Q4pQ+FXmj$v^XZQxGoUmhHPi*!mqKh!#2(dU66%f%N3dMXts4 z^Cf*G(wRFKxm^OeS9-a)lvcl#GBc2SkC&V4@!l55-RI>Nd%W)jau4ZTyJC-DaQYQ- zwW^`Uw0p&V$%gN=?ia{z=4F5Eb1w;G_wlk1``ix(vL|`j%i);1(q9L%S9;lNB%5XD z8mFPfZt=1=``l*)vY*!3;fkN0^4Tv5<bSO58GUrw1rG&sb$`Gc-c4a2m8TAyyss_& zQ5zm_1b3f^AztOH>+q-1Q^ws3#N9^&?I<qST%2q_adEm9f=8YPE_1e)GH2@rypJ4V zQ>gf}og87)rvyr>BE_dy;fn3Y7W9$+Rjl|>D_rsMu?3xEi&<;=QEd@KNbuQnrB)JL z^1;@pPa9%Lkq1*Ro6PuwspkzD%xm)g(i}5B)KB-gkuZ>`gM*9=!EO+=)CA#*&5tY+ zio=gB#Y)IdDV<=oz92w2NE2ckub;ilWV2%~Fxh3sM?i!{TVM7ksk7Dkazo8|?)3@O z=qCja1&V^gaedbRyx1$y>d_m#YL@!g5Kn`N`B58gYl?>8uixqdMfl*;m^|ajQ<>N_ z{TUqPHjcUF>I~4g2i`}Tb&f;}?hfuF&FbOXm-X(M33`oRNd85{=c-oVKlNFhyutxu z*cuj(UzQovSExrY$CJU~ArQ2_#AI@CSld|I!3+>(fdOJED1Qo2KJkZ?qY!cUq0B=k zq+AA>j|M1R=mn!zQ93EJuZhbn`9sS20m><VNcnDna?Kx67Myf#yz~?5Xtf?>OvIS+ zmKKQp*IvMRJdn%tnjk2UThEw+yy<X`#M~u;+@j-hKMdp!IWD)GsU{^)J1+O8K<;Ig za|=SI;^a-x2rE=8jG&dB3#VGGh8en4r46MvY-<K*ml$%TjM2A02V8>8Rf<p1zX#q+ zo}^!`_$VF2QAh3{P-}2@66UoC6*_2DNYL5=T)g=yQ_?I<CDb}~4vJ~RXp>^E*{{pq z)Njn%s+!Bo$IL`;`EGrYk;NFZ8iH6uh7OLIUVkpQ)(|m(cqZ_}hMuU*qY-wi@ut|? zz7hU~i9ts>V(l@-AO5~(tsZhg{kRxm+zY^^k3S)y`T%k1<4+1cU@ve9-Fw6ePXO0_ z{%MH`KN6Qd|BUqcj{C5<t+P(o{xto^;yFv5<QC<FLNpgdV#+*2c$lVqSG@u{W6DEs zXx>c)V+~E><k8EAk?Q+T#_Y~-YObZ0^LrihfDA8@O*bNFyd|J0xWw4Wb1Hvaw0itT zRlZcq4a+;G3b@F=0G5y=8V-qN9zZ2JMi}kB61?V%7!wgozm`}!4_HUJbov{?GhYHO zw@!a6cscOia_#ir#f}Gviyi+VCi)e)Hkrm7yo_V$<SEKw$&c9ckLHSQ1LeoB?@j7* zliG(*Pt*~UI?JSr(HmW->y!(3QYw^-dKsg8_eF2&cZQ)!G`g3M*K+SL_Mru>!Q2Jv zY~d!f!Q2Jv+(mH6IV_+Ve|Cx3JB<cIIxsO$CvG>1Ls^rUg+5@l!#^%Fa=rp!ox)c! z(+|kT7p}l^K0=~=SwlxbZp@+}@^B@Pvz56Vx%3af0#Qz`HS}E+8?!#cH&Z#o&M81A z*VIBNE-@@06rqun$i-0(t*C`*Im52X#TJ1*d}P&%`TRm4B0lU2uqOS$M_B!t#V=$H z#h(cCPl?1}nV3wNXjZAAuI8{Jkm@T_x%>zgc<O4{GyOBgS&IBJZw>2-Sz3+mRPiAu zaz2(r2!(MnbsFE%Wo7ga`BKXjK=G?nYs@mNJvE_*dKen18t8A_)H>d@_Ua6w!^N&p zCkYhc1D%j!JJoIkV(Zr=?NGI&h`V;U+9pX%9?L(Wq}iYhhm)qxEC++U9~p{5ourjh zkr8?aEJ+s;gtV1R8HSci;+f~z*c#$))}(DjlAU`<q<6E1dO>z_@#9F*`%tSL>xLBB zhg$8Q6OoL!iqVYKxZxkaq4QPAYQGZJ`%tU>Mp*Adt@dxidLL@F-wEeOM&rAhrHB+q z-XWp{=@j{fQbU6DjFct;2@BFcQj18EAj2X<$&)NdX{0$+tLCUV_%l9Ijbtfm5s-5u zQ;4K0Dm*K~S0$^(1Sx0yu&TLg7XHkS)Te-2sxOe`kpU#jQX_z@h-_s}w&GihD<gNo z#j4d++~2v1ccoa>nyN+kvnFyntX$1p9U3`{h`Bm6GKq+}Iy7<~rJ1WkBNs5IjRcCF zk%y}TX(zhviQGvWbWqoW`dKSwJ@qmBP^)cbC1oFKwVMg*eW=xLVRiLB)M|H3L^5BM zJQ->F3aILATB@CT2>_<DH6@id2TLli4!svh4bmpdnbvS8yb))Gp2i^SJi|5%Iq-4k zIr>YrGmsjK%>NlYvf(+h@Jb}>4bPE9HxdLZOqNnYXVzDZru4{1<>U&^l#>MHuNNu3 zC{ZiK_aQ~0j#h|Qji&TTqB-QM(Ud{w0+y>rQ-%=KSB<6&m1Jn$8)+e4HJWk?L4DO| z%9y{Ai&u@NjGf4W<f_q>aYF#=t434CGhJUbnlh2;`l`{CDNNT_ji#JS3+SsxQ>GHu zSB<8eHxuG{)o99@F|?^%HJY-Ro7#0fmq@DAb7{PuxgeE#=2@X8h_)%qs3kh-Iv6zc zyaRI-_dp>bzL8qJEp-a<O3~^aY0dO-PXAvc*mwW0hQQpHauHSBckvx^A1sC#_lriT zn|p05bZ_?-d?&kSgR+|YEWRE0O@yt8n}N8L;+}^fSlxXXp(oXy0m>R~CL~1N6-ZBW zcR^;%o!$aPy6+&@bzg(z40i`|Gu=H1WHsF`Eny3{0n)SF_duEL?gU)hy$Em}w^d_= zM7KZa>$>SErJnnbCip?aU73&l9PSXv%yoH$K|}W#%4+1^T8Lc~?gvO|;$8;crtVju zY35!Do%7s(6d-=M|AdAGZV2Da-FA@E!fo0Vi$(WE$ZzFl0WNf(LG6lM7hJ{eAf&W* zuZKQu+~<+f)@=f=cJ6lQ+1`Bxa0mAqSf-;p3Mrl3`Jn9VZh;P6+|~H*>V_b>#61^s zO5ACvbvO4hz}?-B$nD|wLXGxVZWyAUvfOdd_i4+W50+;v_agjx)^e{0({q;F4_ZBM zx$9Al7mx_<y_VYo#qG1)dyx2|<>rC%CCfbmO<o2iOz?{3?g!timb(chyk@yGfbF;3 zlR)yi<(`K>Z&>b5NO{w8e+2sh<e^e;S?=p-o3|}D9|gT*xpVO6pyhr7mEN`7M?mtP z<qiSE`<6QpcK^U~pGQ?bwA@d@_mSl`LE>L6_e?19vE_b&yiY9m3jF!ha&N?+&n)*Y z{P`Sy0VTe$+%j14Z<c#A{(Ol%wCEwreHSEOS#AXN``U6hqV#Vpw+$G+wcHDl_nqZ- zMveY%xo?2)AC~(SY<t*pUqOw&x7;;o=OdPTF4%vt+|gh^irRwj7?g)W{%N_}q3(~C zn}NiiEVmv0{L6B4&<;Oa?n4m$i{*|%HGj3-qp0+6mRk$L{%yId!1p`eUO_?2l{*HM z7b<rcNLHXb;m=CtJ_*W;l>0Z3T&&y_kX)i%J|VbNxpQEiRm%Mae=fu3N&LB7x$B_( z70PXjs;pLSUzqMn<xYc2S1GqUNUm0HHzcl6?p%njP;LbZx<<Kgg6~@8{tC*q$~_;6 z>y-Niw7yQcPe9M>mHRu`*DE&y_8XKt7?!wEx%c4DUzGa;6x^WPb|AS)xo3lYqjFz? z2{tMB9VBj6?qNu|8GAHQ&@IZX57XVM+$2=xHsvmZF1IT;6MT0l_jdfbQ@K09w?(<N zAo?!l^4RFRmD?3E?@{h;XqByC0Li_|ZHT=4z<|7M%3Y2>+m*W#%I{EaBh=`A<vt6B z2b8-A#XhLqi($xzP+Ral3<enM5!46;?NshxLHVe1hl6jIa?eBwyOp~DiH|9_9%}oz zaz6pz6UzM-4*euF!=F9M%|`v6Qtq|zx~E|YRP!0w1q{z(%PMqv4wgqj&nq_yh8M6W z6}o(*+;c(lt#a>&%<q)D6_kHh?j6wOAIjYTnTN3#7B%`FGQn^}xfj7^KPWc@&5kPf za{M`_+;gDdKb4z|5`I+fc@XxK!h{23SU9ymx3kKPY^eh$TKt4gLZPX18O$@5r!HyF z{AnmFbs0f~WODSuKN%#_tkB1ho4Py~DWP8?ka_J?P}%xq0^126!x*Apu&A+QHHb2& zPO@q&qj)P5FId!A{#FPjSfQ6v5#m=&1x0m|ZNa~qmw*Vn`$ODuAMNk}lH{&oeUGNM zhqFa>@asLC1id|+lAOsEQd-7DaK<wA9!|pE9!|pE9?l_P_4aVy1K8Wc*(Qw8jUk+B zhEkwNTFw(-%kuVcE`;7@4=2TWdpHSudpHSudpHSudpHSudpHSudpHSudpHSudpHSu zdpHSudpHSudpHSudpHSudpHSudpHSudpOw;-X2cE-X2cE-X2cE-X2cE-X2bF6W^T8 zw?@*sF@5v+Y`!&;)}6?f@!5Q9B&`RL?c=j=sR869B0I-hA-#vQ1gy2kyNKa^LRPHN zdtlDwm6frAzXG%}d1Ym+<=23nOePl+jAi1=%2+W$ePv~=?J>am%F0+f!ura}SbM_y z%F0*=!ura}SVzM8%F0+5!ura}SXaXO%F0-G!ura}SP#PE<*vP0FDs3PJOz#r>rGf+ zSsClwAAX{*tc(pvM!LSTGA6xhmGcd18XLqOw%YlXyn_j^aXvuhV?zk9buI)~Y$)ON zP9u0#>=eQqoOJZ6*f7GIonJ_QD&gClyGef<;VsS%%0GkfR%c%|z@?+nIQq)U*qKa! z(BZ-`cGh~p`pU}KSi<_s%GkJJpx0Mc#wL<}zw=x==+7p6!1*y5@Fc<qoz*PsoEJlA zHo3Agb}nIkWo2wyYvdlz=9QJP>4bAt_Ckn`ozIRkOl3!5%h)U;v5DEdvNCo7k^N8C z;gyxK*+h6{Wu39)Dif}Yfbz=9Sh?`w%E~&tvNAR=75u!ivd&Qw&nFtZvXTyEuB`lm zAk;@sK1}de6oYj-z+{K9#=JDyl5!Saj7)tqWqNbI9w0YUrnlshLf=f8-ipfseKTcx zAt${0X3F%UT)2V0nKHeY=F&G)rne?sjx_)#`{`}!L8iW$GQHg!l+Ool=^Y5_n<>*f zN^&M|rcCcdSl>*U-WlN@Zl8gkmEMIer*EcA?@E|AQ+C7O5O1bTFIfV%EPXR&diOao zh~~|d={;vlG5qx={Umy-zL_$;7gf|ZQ>OQ3G5Ti8^pgqen<>-#3<0cfrcCckSl>*U z-jBTcX3F&bg!Rpo=>u4-zL_$8AmM{n^@Aw#Vt_J!Kv~{QnLg+<q*l8cW3Qu%cvx2E z6uh-AR+AA!wV~9o6}k~5s_hz3<mkQCOt;?$URUp}=EAX_m7{le)4}Z;@T<CdcQ^66 zw=hxqU)>8pY!7AyaW66kD%CSYd8#*98p!WkJwr56?iaa8?G+M>bB{f4mLY8Aq~@av z4aj6q15-oU6W-u<;98#sMxTSlpjgdx`x;*#!RtN;<?Yp^vl@+P3E3UI=Py?%q~W7B z^hSd>mP@k4OV+*&R5rGEV9_4~<xBsah_rkKYZIPpw$MDq8IR{ss%tZz)HMuwd3T!h z;f1Ie;z>T9f|lVMFZi#2lf^NK2Q}s$2~ZBul&bY{gsrW-I@fDHiYz-3VW@1GmDejk zdD9<K&I(ZSRA;DpeBn^s%DW~&`TdD0m6i8kfHDUrJ%P-SRq$?r@&r`)5y)yj7VWA| z8UpaJ;lQ$3K5D~-D51rClf4+GZ!%$K8C-|dKLEu$=h@)iCXZKQ^i6zjLSW%XZTK7x zsc$#grU-X`70bsFm~E*Yiq2<OY*|*+miYbhv<8DBZ?9Dk2sV$@Z)38j9#RY-I2dAC zVJfDc>S2TLTvjYD{-~mh+pl3Mic&1KOG|6bduj0-LMv)hET?xoCYlZ=<xvDv{A9qY zSj7`rjVB~?9Wsk~L#=vJ@H+dkww2#$pAvjB@V4~MmZrY5@bpqWqjuooNISY{!Elo? z6TSq?N9;YuDGlR7lfRja&npXMwI^eW{lh_OgM~#wg`uH8##_(Jhj-I&thNjr_Ziat z6!(^D2XW05dT77b0r1Y@l>~T)>uvy==Q+buoC}^0)wv#z{f6P`Mu0qX0BD|f49{}% ze55v<nCEfwbf9iCZvcc3nnynBkovpFmjtVbey0;)SyurlSYlW%m6~(A1Zz7N>>X%z zFB>62OZ-~(LrY3<c!2zWG5m>^%RZpVAqywX#`0ymZ$92#;C>ou&dr8zPcEu=L|x_y z{e?nn@u?d=i9&}Np{BCMhRCn16?&gi*ciP*DwVyE04w__fPx-|<ph=Wvi-`cP`fNs z*^kJ7R+W0~K^8wJuIxm^XR-4|LUTQ#&EA60gH;Os$p|&=@QWeBL_<C*JM;jg=pIn* zFFMih0j=IOWV#V^O}@|knL6w<x2(*32rZyL;sHG?GykkwWqTzLuFSk9QSEY*U)xB; zC1?x4EbcRtmA}#uB(`)XWbs2+T#CP<$n}*Kd0jp1D{^aPMbdo}<jE8kQf`Bb^ORI} z@S#@TdFxq(PX63a?s$Po<_Mbiut9c#HHJ!n6+ZxCL}M(q@}}INMZAaX4mz6~-k2|5 zFC8f_-?Sa6#&}fQD^ndcR6m1iwJAzQSyc=(MC@T3bXn|6Wl*i1sqx80sDh!#Z<8HM zP5MZr=Zy~#?F$giFzM%jsH4|Nvw>hn=%!)evkv~Da%FO}-O#$ad<--#c`~iam)!j( z7h20lZJ343Rx(iJ%UtM2G-hYU5|6YedqMk<_T7&Szwf*K-Zhf&%#t%P%hX#&4xnno zj2w7SePq1}$zAz=QK)MNeB0tCVMFgbd!NvU&`6gSGnsyAqy5rKx|lqc$<I&}(~ZSg z-79DHV4*!&W=~eEa<&?3D%ZDiaWnnm;QJj+?kd=wj-^|>4O&~Z#rD4&*#raWfL_z{ z$3%YAhTkyAwwN&c97E9mZOj#9(3ELv?RT&-;h|g*%1UuH(YqS~mBr$3L|;LBsZ(gv znFoQsKy(<<M~TYp^)${IMnU0TGJzfLqtdn`IS06%xiZq9&Y5JL_kh+0pw57PRu7^w zDJUg6hp0>gMzNq;?*si?0f<L)x-pn&o7O<b5M3c?OQ2^FP5l75w=;Jf(cg&PR19=H z(Y7A~eVw8v5WSYDOflqFkJCQ_Dl?38WbRA!iRK_amuRiO0&U+6=v1N$i9Qc?)ik1; zfcECe|7toHZP>sxv-cuuHG?gHDbo49TQGMfA8-Mk*_(%Cs`EK-Pq7=A*4~8kqSOVH z_YLGV!PS?7H2fH4y-T&rXxj@u0a}7*cB-7{L!Sa&$@$kDqK|wA^h~1jh$eqdv<1-l zMB9G>v@=C5AbRoNuq%_E`MYs3jEnM7Ymd}3;r9S&3Tob@(-Xt*YNNLi;t|0gwU7-x zF+xfV@AM^vw5(Fdokj@UIjQ2n3|>DeDtXktN;mO$Z;`fv(t1@X?diBQnVg6yk2Kp; zY~w*s6rR>w1!q<%>Z7=*aK)Ax$wn`a*w<@Q;|4~rNfb7#N?||8g~>=IdU>S2!EV05 z6SbG3F0E43`1qigRB>C}U>>zE?UpA!X)V8kw2f6ttA*aikC=adT$)GiSM%1CTvN?8 zl=fhi(pJTFlPR23(<7}T1;O`jEA>PjrKne{6xAxI*qWL2i#~MKoQ+z{ERGJ3Z1N<P zeho?8OkSd!;`bo=po+YILA#en>ep}Q*Pf`yC~A0>qH+VGmU^N*Qs2EE?Fik(Q**z8 zsA*M->KPY>mk50K@`!z7?ON;!yNJRru2R@|Bg|CJBl3mpe##Sah(b11DP(z~5Ra&q z7!SsNEVYrT*5Gd;<e@5sY>8J()<WU|9;q+t@iRP8+bQa$Dn;!Lh+6C!+avXj{lsma zsLbym>a!|E9g2$zSM2qT?GgKSdh#nz*nA56tx91I21fmn%6UY-kUfQ19ZU0nKp|P1 zG;yL+=KDhWa7EVJ5N)Sde?Nf&xIXFmcK}>0P9ebc$>jj7z82KHwHeqxXQV%72AO$% z_<U)QCkiy`pQnSM*;piRqlDoAHvIz=zQ;FfrS2@kvon;&dBrk(<E;jC6U<7(m_J7B zd*9P!Sd#I%P2tUPuCykaiwnUMb1?|#%?+^i{gZ5XsPaUBZONZx3t4%|x5Slv@K3VY zR^HG6+c$rbEo|jo7hr1yThoyL$s|cu!N&o%Kf{75HRW?auieI@&D4+0E<w^6htaT$ z0Hl2nTfeqh*M2`5_7<%VcI(ebMk7fBOWRs`-HmNY_JUDc=9PM3PY1B_E(s8Qdm^G& z14P{J;LlKll4_aivbYW>A{rYY;*Z`{O1dLJwEP4_1&0GfRY^e)It&9o2L4`yIU9Nt zvoz}k*w5;li?)Bu&-j5ENk{M{eZBdufbi*{|5)nh!I+3iUoQYr!FZFO*w;TceH}e3 z;!pO_r6lg>t5LZ8#p`F-luNteU2ADI=(7j<bb*e=vpJt^Di6CxqAYnj@|`IUS6^6a zkQ$zElsV}KxI+GIT1zUk3u?j==0WH3gE|L&JY2Dp&M`_)aq>P3@cjKx@;r2VyqreR z;7^oOF!7E!&!3>z3&V4aa%))I_DanD6l;2YK<nEQH0Ttp>2_074gh(n0S(^%PduEn z<=q|NaL^)gy{jmN90eC_sj8M$P@6$XKfrkDPR*67|5$2^nup@_%JdzR>90($Gp=Ji zbiXMw!(;yYW8f82opcl`eO9GPXCw;oh_XE)|4_}1kQo&6&nkuN^oKNAVE<x>YI{P? zQNuhbH&9CET{<VRv+Rwxm^Zx@aruV2rYG(yb)6^fIg0C6rMLx&H9OT1`L<pE283wS zo@MfU)AmW^omiRo-e?PtcV=bYgJvddnx(8V@0Ni+@3P9g+Y@=$n*2Im%|BfaUTM<r zS@HW!exe<h$AgY%M+sri8R~kTwD&*sq}4kHX`fapZJ6J-d382x&L0rVkAhXYfz`3l zBs<0EDt!&YopsF+w?GpZ6~h(lXQBs|8loN`>ZXbCKqK!QlRN^+6N9|**lFc0Fhu8r zh<lp+0z%GmgxPS#a+Z*5!s9wnZ8lWSE~}###<wCpuiOyv@d|g3K~%V6kBpeAEo4!r zn+?q)U`WM~5TMbER?t;jYE>Mbk=%$6-Z+&imFolYdYTUVF<6J6fED+(vpl{=3cjQY zuEP+M5v?&Eh?tH~8Zmra*U^g*^6aj@X)rznyEIUM)v>Y3`5Ij?uU~-dz67$t0kV!) z8bqG>d7j57ejRrPb38ASoNrAI_gCsotx*g)-Y%Pd+_ay(g*$fpanpYCT?G5f%~<)J zL5N>sj^=_BFHrFJ+x|Z?ytf(xJYw%XmdgxlAT+?v^@;dq_mmwEgY-|JgL9GS%BFs1 z^O?QmSVQ<*?Rq5ff$kszn(Y!m*3h3}gN$jRset*^R<f*tyh0#T_Cy?DA|GB2B82Ci zd|)!P9J<x~Q3hc?fE~0m1z(V)zpQ~@H^if&qtv55G#(^hO$hN;QqcjD_<Mh{(;O)^ z_;Y`<(;na{RFDs8HPx_V+1Q&jm@O<?Sh7LC=4Xlxqe)KFcU9dFX+y0{{3d^s><_0O zo7(W2icERb$9cZ44XZJTU)JD52z{<~1m9GcbF)FW1JG9LM95fpv=C0lH}l!?H6gPH zk<c1g4EN6NML7%ry8PiS3t)}<iuE0O8sVK{xpt&rqArOjjL-#tYVhgV!24jtI_Fas zV}O=5Gznd^)~mwLPOtgp$L*p0fY<t3vaa^Cq)~`MG@rT+%?F&(D9i?DzaK=P9^PU= zVX37oY#>hskIo>-&Z^BtEZ{pkLnP#}<I&N~qRUrFD17oIEF<2l0qR#$xz~VaF_;%4 z2DgE~EBwZL7jp3lx%%(3@GTs)%{LxG`i+Og8=?N_(C=_H2(=fEg(SHQDttgd{f<O0 zrs{Vj2%5vcd56?yqWWzJIh8xP_<p2#Z$q?!CgyF3u1NOYhPaWSc^iVT_cjD!?`;Ue z-rEp_{kI{A_-{iH@!y6Z;=c_+#D5!ti2pVO5&vxnzH8vW4KWLd|26~__TPpe;=c{C z2#EhS#4sTK+Ys~~|80o5kmkP)aS0IrZ3u>v|3_~_%z^;_Z3yb-zYVb(<sA1m1S@IY zh9Ky@4Z-SqZ$nTB--hUnG`;z#`er0i?bHeYOl50I>IN^BZ$sPyq{e0tm^-A*#Zk%5 zZe&E$1`Hj*O;`T{5}P<@ilu6k+lp~7k%k@TKmkIxq{kfIM62qMJR6QB7fPi!VA?dM zsWymw?$nvsT{4YehOo|{NZFmFW{UJ==P{(DpHIFe!grp}w<ONDEY7!F_-g7i5NQni z8gSIoXCMkF`+3HZEDN>fxSD;Xi(1!_w`1)0KwkUOh$Jv3*S^g0GwaBCjGC~vh|E!x zY2{e>_Ihy_^k{z6hWd!Jbz{g%{+ZvKf^fYYqzu56t9~;8YNVCkowcmTTHzjHSVyc} zkBYj}C*xeB`t+7sV%Pe#MW&c9mkd^e9%ODwxcD9xj=@C#ff^AEgt;QEC8Ztu5vWLP zNr|I>!u}#^+Q~5HHiM|bMkgc5YTOy$yFk&n5J2sJ;dcpU*E<E+YG6(K8m8UV@v{XI zn_;Tw<XU;NO#16cM_R;w=slwk{xtY0iXvK5+vSF?uWz(e*gO9{3}~t~wS5|;6u{lu zUIXf1h)7M^vG<?%GtgP(vn?g)??k0y?OCz@zhEQHt+b1vj{q$YlXYOh*}vkqu?5T> zcji{DTFddM+T>(dwtNQ8*f@nkTCE4|A)}<fsyd}Ms2ab5ta%XAm^YK`A@C4@e-gM0 zK(F60@A}2Cex~h!2V%|mysVk*6=^1OK3H+S(I6EgL~Dqq6&EA@5|hq-n*&Vx5=gzq zr2E$Wmv7xdHl<_oH#bB5&U%l^vN`8NBWcm?1lXc~1JHz2(xP?$jWT&?BtLA?$4!}R z(Pt}{8EDZ$cFP`y;A0lrtDqW+xERTkA++&A02Ki8JX^O*HGc7#(cCkO>H{6t8mo-~ z)hQ4Jd*Dsxk)Vm#c%MXnnr<^x^FVchrh?Tds2KKDZLFq`7>esbahXqHHGRRPvyL~L z^ra~G6O(=~=pPNxPu!}Dd=lxe2h#5_>1>C?Iz8a&c@GA%r4zj7H&ao6IFp*R-%#Y3 zI;jn#;r_YerjzKV55Z`~pBgH<LF;b<h_MTL6nC(y)eLxYwln?~p?UdH8+IX@X_2cb zGV^zIF!=#;HFMr4`fp5R)apGzH(APRerh_<tJwYWm9h#sO>J<m78lDy*7bjfmTmeY zS-zSuvEFc?gFxPvcb%Z;&?oNPuDNRKKbG3u3uTC3?68&giw^<h?J<PDU-W!mvv__H zaxf_pnZH+-x%MW=tV>@@v15j9lek=F7^1UxXi2_kk0vg<B|P&(BbEaIazbUXb`09` zGe)vQTO>QPAgMtIG_;Z{QF4vsER@fW+Tg$uw5hkz)SXa%?zG7`+I2fky$5K%%b2sB zrtY5vR1TZn!QA~sFJbNu=9VU-A<~IHz+yipT8HR^q6;qE$jENsq0MFdl$_znDUeZF z(7U2ao9&zjL`TbSil<)2yjYsz2x!D!_0wRl<%ZC=*Q`oSfo(BX%VB8pFCd^mV&!wx zsTa7dydlOY+K&8Pf!17VtchM`6}5+z)R#SXX@#2VKd@deq_-E}|B}{IBlDS}zNGLg zD7?Yft$}|}H=kv=SNH?RjlS)_C-*yG=pg*xlV6SKSWfHxKxS1iwcJuincg@C0iE<B zl@qB>dXXyNIxr;PO|UbfvE{rWm-Vu<cVUxQUC$-KP@BQM3x!!Fj1Hk1iZcq5Fratg zG(s5k*ELYi>b!=mB{sETx9%dTUHKZe^O>UQh0W^rZhb6-<&E;OAZ0-8@(@buLQH>A zyw#bnedA_SieWqyb+k^MyQCxQyAX?FAe5rI^ddi#tj@>aZOKPMOkv<Ns%)TwKZY3c zbV_$#`kee7d31uM(pA%FMs+)ygKH<;YOyTTy@^%5dUqsY=4C*Hif}E<j&`ZuwfX== zy`(gdKob8Duhz`sA16cE(dyMnrGQ3i_$-}3onp|W0U1QAdjer%r3Pe>qeer>DMDs6 z1FR+R^Rz<MqqZ(Mul9h9-0JOWlQ5R#i^k+K8})GuQ8r7?tDP&QXMn`<6wYiHKxzW< zt5T~voF^->6k4KZ_VvA_sO-2LzOi3BE{SNJxGbVM^;GK&vX@pLC0f)?!foV;te34& zFg3yYm&4yf*%iH@bpz&x0OSe)0S&8z%!LOwYR4?3G_I~jX0gsqDEl-Zp6sTcQ06w% zj0E%II`ybcBj(4eH#15zmPpMClBCs|$8+O(E&Rl!cw)<7qL$Grm_)&7ivJ~_N^~YC z(U~IJ<Nhn3!lcGZgBar#bi$Z89C~cJ=WwoHY!Ypm5ms@B#;b;Qv@V_l)XWH^)&i2` z`FvJDO^D5|sc1e*s;#YEhbhE!q#&QMuAs@DoO%H{n8DSDdJc`-z_&LXJ>DPSKXI3C z$o|kM?zZru%3M^SiJvG<>~*cCMija!yvj%sB(E|9rNFnmem6io-|skZFVEEU<K{*# z0tV3*aVI6(GJrz;RzOWNv3nF&cKsr+zZ83Y0Mn{K$7)l#AGQUZr8{6dkA>>D_v<9~ zOz8O?;ySU>J8Hgly=t=?cQTo<4E6796ebFVy99E9c8#NT;dLbeV(@kg)J~kPdq8_h z=n?PSJ>#M*>m(grdYLqsR(JT`@md8t{K@g;c&F~86PeHs(Sk<l>(d1~e?LDFmeO?n z3oQocyxL^M^2Vn~3YI!Bp6oFW(%s_!;#lE@ga66+!){449ybE{gAPX^e{8B%XvPe` z=VW=_oh^d^90;S19u4X+i#~MxNaMLRMw>uSs2_Ko_-Nw|G7Tvfu_E3%8hcV$fp~;K zlP7cyFG!fq?1c$~1_mJZjr@3Ri53J<RIPd3dD(MX1UiFQu_ebpM1){EB0@rEEb?9K z_+DJB`$+3}F}jbmN#xNUjT2WG_S$L3*3$_+s>K6Epigv&%Lsb>|Ft7vR>J&@W1;Vo zv8=$5#%&;$n>bWvB#u{^apq1K=xTZcX)UkkWF-!y*};Ldwl|R02@a$f5#s}C-T25^ zPd7?^Z{%!{I8^2aG{I2WP^n9MnK8FfLyNP?<Ay&yiEI)dk?`OEzGpS_+cRNE%nOc! z2?L()=z)<=`?KG-D@~&k`VfBH67!oOgF_x$!we{ezADGNG)6zK;n<;y<E~A#b-Xvj z$2FlhDQ+8-nxIX)z?dWbuD$Lz9lU^m0Wc6&(B?WIb@uWZFuLfX%@B!I0E=Ko<q^*d zKr+&qIjtV)0%}M?&tQU#ctI;+<ZFkvX0>|<0t6iLWN}Cojq%O1L8S>wU(>86YW0H| zy*UTu^$*AsgA9-=!%Y$fG*9MrdbKbp-ir8rE{-s?4KW3n1|J$n@rcZC81X#aG_>3> z9sW+$k@~ctQusMKUI5305#A^<(xm$ng45eeTstF}PL)diV#UjJ5F8ax3`Vsx{bZ=9 zDM$NBVAn}wjt`w@X{z81W30~@h^FIwR+EU|gM2!p-~Zl};eUO}niwwAyf_$3tb#Yq zPLKCtgjxolj6}kO-kBMvrmqK9ux!Oz#*>UAX9b;vK7=K#o-|+$Vx|$nUYir>*L8Id z=B%JzTq>u(_2a%nUuzIYsZp*LXnKA_Pdw%peyswIZI;%JO|4AGYhnsCXj4-HP!`xM zj<U|)9K#Ujv(7Xb7RM4d5R+Mn!0bW~`|*ez@OXq`4*RVV=d*zj9P9^`CL90vFL^Os zI`KtpEYVNX6NhyU`eshRVLihe)-yeK#?se3;}J903J&X8-msn>9M)?Ghjm&0>IHF* zHo6S-^wN61r%20q9i@KU_2q$y7o*{G>@^MJ;av~LcyQv?;JA@Lp-%;de|j+8EfD@a zck`yS0soTGAYc1eLEO`u2f9&$mnD?yjrx=e{k>7&ptxAgR|2{5Wp3pz%|TusDA96l zq+5d?(^uWm+r_Qotw!3%MPvJ`Z|mcGWyi!`$%QWMVmcZZx@MY!@jjrIxC4fKPS!Ep z>o|iu@c=-x<CnBS4H7KW6XgdAJSkv#cx11Dc97dUt_~X!D_k80{Iyh{00HRxvXNS6 zRP+MeFCk|2kIz;H=nRbXfx3fX5Yo*<1aD|ZyXm;X!QFJ69<^EHp?(Fc2ct)&fnE=q z!{W5@h54y|BHBpPou-q#k@N(Eq4!{wA<cV&i-)=4_`}@ep5OYNT70|mvo;eG-~sX+ z*OQNDxZZ=?REZOa(lzw3ikpgqPlEqor4fuDt`|SB)`$lzt~5-?Wbr3jY4}glvJ*oX z!VgsOAFS00<YKju;~P04=-{!f*O~}SXiclWPbfV`#~Q4t<DDTl?r8{1#);t{!7&hp zB>1{F0<!zVeZ3LTpiKkaizA?PbCBf)JAZy4>;$8cudh@rq0|;}<ydOMV_k1PYli4n z@fwnp@yT1Hz$!&?6c+OrA|_OLOKzYXz}tX0(68GDDkrg{osOuo?qCP%5bXF2b9?}2 zx?iWnsiI#yJctX5MT9yoAmCY?j*%tt4&Tj-o87&INe@zC4^vPFtUiKa)i0E~1s=iC zPF`4IL!v4t2gFDZ>l4sY68d^i`MC=5;|S*#{euY<HbBqi<Es#9U>zU^=`nS1yzzsv zXNXSr!Uy$^M=5b@E#;K>+B+dK>D(&gk~|0uJ}<#uX7j_15sc+Y;`HkOo2MlIgV@D~ zA8Cjhe=unZ`hgAwZoE%n+7xdy{8(@NUP3|5c+0REyh#p@3ietZzeb^vt!$sr#2fw0 z0yB881LDUgQzkl?M6yalpZxYjkHJh{5676p>*2W4&j<;w%-<4ByrnBQ47#fPuAsXQ zLYEfWM34E2zeWXuk{_+`Brsl0iVi*r1R9vDGZ!~!Yn!Cw7dm+gNQaf@fYjIf73}!m z27Jp^j<)=<zyuI8e=_S8nLuIsq&t1Pz#IY5$TtQo*&$E?pdI7w%n0ZGCV-aKlY-8^ zDuLeBMfcIJ!93lwO5#buZrjaIPMAq_k0<L%1H5J~emf3X*o9yz^-Ht{zOkDF2>vfD z8acerX~Tz|)Voj7-~qj?qB&)=i>A&zd-|M7lZ)ne>M*WDyH?Yu&YUy9)j2cg6iu9p zBN&Bb`qYU<=bU}^@g(gEJ9+#G!YpgTq}g*jx9!+^+@v`(W)<S1Tb%t=K56RtZ3@qY zc7SJ3oq0}Mjg&8#HMz`7pEPOm6u_v&oS9R>0vKChpuyDhH7H^<STb?W)am7|rq1k+ z3Q|7Ebk0<d8b3jY_IF}7CPH6Z%5lS?kzr-0>{{9NoN&mVQwpSpQ~tv{T}Kh0<&+~~ zSg1g)?Ai@@5%Y&TD=NaaoxKb2x#eee>0Sh^=0;%CN(q$!nmGlKJB3gQ_?o>9=qzWW zJ$HrE&1v+fSSbE1XD?YYHvbnKETr3i%K#l)vB2rO_H~^DB!d+_-&x^|dZ%l*bGjcG z)wSDM9Zwo@ZRa5)ujw-QbWo(SO63Cy6%yJ=h}L>!ne(}})?SNJb}e&O?1MF0(?Y|_ zyLO|wiin&_a~08CBWSLcG}j24YmY@;dc$7xV6T1u4a;7z?B4X>aIlbW;5g?`s)hP& zv?C?pvfHnLvgyu1C|kp!;$;HY+vT92HN*~#kktb2{lC`pOy~R`cEjU4Y}o>@OP_!C zgz0|YEi5eReaes_rwp}%A%dL_dwb)3`P|9VXHA~%_2xhiPVCz3hOMSdKYv0wI-_)U z(=pMh1AV=G>Ws-CKqA<6uSZY!d%aGVehknH009x0ZL-{%ECtE4r%stNVcewIQ|Cg( zb1h8lB}Id0pFd;9`7_7q_<*eyet24VcE{ol<I2h>lrsV$N>$3y97s=$H9EeCiZp}P z0LB7<jWWIr34V!U%O+2sGOm1b8MTI3#-~^h{zZJcOer{*Yo9;RuIcQur<IJZxVECA z!mhr?Y2=(UxW(v;tWY@QbazJ0ISk+1x@;gkc)CNM%w*4+PLIsoC5c-J7V1Q7HUajt z73!%%O)>%gxKzU2W$K6^?2uQe(h49)m$C<6s+@tn?1gLW>QlmD`<<n5b!Fe9Hg1C; zmF$!xI}4odp#D^-H>$k?vsY|X)Iq0j#@n&By>8hWr2oTmNc4d)Y*EgXOBfVZEejPY z<nFbcQsnk$G&y8BE9`wsH?o7-WdrS6u*7*KV?0az&AIo&QKJU8=pnZFn=wW8|H=|M zz9CK*J2a;mPG=okiV=p>1~~6mOprnoAjC2ICF?j7^dfC{)~y%o-<{Q$v^|K0wmpZH zPm{Vowv42xs;>LFy6RJ<=6R^ObGiM6wXv4-O)ckJr)OX2Vvi_y=AT(nvHPjrcFrzD zWC(n6DTC&V%3(7<Omj-(?p4kjXU@G&eWdPO${;=6Ve4nEAQ*>A?IwHeG39m>XRAGC zpxp$u68@J|sJn5Fzb_G^Toa;I{=S6uUK<j-e6wT)kToHvTr875#VOw1wcEKU=F26a zscgubLKr!nZldYsqUq1dDg9#QzB1}=>;mz&-IH=*qcfd`&XYHsgp_}Y^eaM6soi+R z(XsZzDb#GOSF4wo=vuAuYw&hL4IaVXQtjO<bOrt`6<8q^SZ+%NeqYQA{OVO8ZHlwo z*^Q#NEP=6<{a2LjjPr{g;}yO3KNS5Bzvveii|rn^X}cE}vyMA;(Jx5R58B3de$j^) zOVNL^ol>vL+r4r>SxlGOYNKhJoW649ILLfg#B8=X_<k(#?e-MF?@L*?+FPA7X*Kzp zL})O+lrssHd}%QzKgxdGc6R;vvIrat#yuirm(6(b{Nk-3c*6dijCchM-<4$CuVuVN z8Lw;t%l5?_*Y`_(w^Ii)*~lNrO7usuf00TYM*WcS>!KBY^OYnt-y!>R-FmMt5)*C< z(}b@tq6v3|rS)E2#MZkvtW6kBvUe_FUpN^09L4;!h`no7_-%n1NG=bTKelh>N=W(e zgr!~)UZYFBPnY_JlzN|(dO(+YkCeJUUg|n2^%p7iEh+V$FgxR0i>S>5;Wc)Ht#)Ju zQf^;FJ=WTxMhe)si<y6|U25-B%)M<<s4e@<onf?#ZNDq*cZ5q<3c~r&ZiPSv{dX)q zassPu1+T8amAV2yNCmEx3LMiFxLhjmy;p&-{nJ7!a$OS5_OMjoMXkcai`ba2g-a2b zCBEFX*dghYwnK%V(%AY?sFd|NBzCwyBnlr|Lh~OChq^Lri`3<ym}QHU@BtM~!o-N% zUU6YKhQ9wFCrR-UIzAj9w?_GoQ<cD+L?%Fb7ND0lW=7ymUlL~zlV{JK$<+)@!SR3j zNdCq6f7nuX<n58yj=FSI*J)_?vuV=?p;oHMUceFN9OAi%u=c`%W9@QwsOj{R$<F6? z>gRTOA-Jy{weAP7-x>~`9#*0JT43dx=S(75<O_%H1WUP7vLGCK3eZ9fx2Jwy+g?!E z+nzjSW!H6fof2o?rj<^&i@RLZ|Dr)Cq!Gi=*cF7>9W?}97+UO6p~lJ{ccfdH{jK$O zE@;M(reN0>UAs*W71WCV-?Ub!X)WaMTo%fs-@j(<vL_C->$4g=FqOgRTMlppD~YkM zU<!rZvy9T-vnZ~u)7oi`v>TVnr2AX&&)H~KC;wXE|Ing<TV<U6&?>cSiau9~h#y77 zv`|6KP*eU7!k?FFMXpf0?6PvZ1_d3%*r_m8qM%De(9c$BC<JG{53Bo-HRgYFb`J;o zFW1$7ykh^4v-`N;>v=C{x5xQ?!rFYo-1%)V#l|F8d-U<00&{kM{*DQ;KY!Qh-a6dt zD@gT3VE#U<{M^}-Crt8E^jbmB=t21Z@{GRh>~kmc@d8RcciuQm-p!O8RSwoTvFrK| z7W_HBSro}^KG3oKFre)~OUsiCpHH`duA|O1%YikcO*nWa8Be>=#ga>tubXQx*gD?+ z(b}46zqQ~<#^8~5WZ>+%ql@f$Z`;L3ICH;Vx&S%_;I+#*QXaN;?FMqSxbetc?*MMj zHT<Yu@4Q2#36XK6Z@3rGL_+mtjxc$blVM+thb5aP+nG)-7W`QF+tFR?2CX}^?yGfn zWY>#Mmr#ey&^fU)L#M^;CZ+Q_&vo8$UKr%`K=}V`31R{y-V`d~8v9e3*lh~!ode|K zCDM8C4xxLl;G}TRlFvbUd#D8P`$Bn8))OBtmC+t65vcX%QqD~7$6OM~t4leoZc)_t z;8G4*n-nHdA^Q_SZjgsO_LqV@g1-F~R}|4T_UwUn%$Z`(DzRfF(*|`NG;K~<#d+&q zS!X|uNRnA%PcPkMXE-IJ?CIrp=D>=%Kh7D@ZBE(Bx%TKac3yeKoYi*3+2stnaQB6* z)zym`dXL(r7oIU!=DVw9CUwj%buOP{Pc3&Ys+i-P>-^vh7~~vvD$0JikhT2-t_R8W zV#OS3@-@i^!FtaiJJs0=wo7CZ^|Q?-g@%7YIs2Ve&N&xua?TiJS9dt^`DPK#bbYw= z=6>_e!#eT6HKC!k?1d$mt`Gd$URcP#KgIt_I`GPWh3@FfhH#JmTZ+FVEM0Z{UotQ~ z;qPPiN0w9QWMcW0##PV-pF5L6-34V#zre}$bG8zq4_*+5cKK;lLU&)od@X2&FUZ+Q zkS=in4B~^OJ~$=RDQ4H)b-6vi1ama|qop#>@yyFvj&EK&J=8)uqq;g=ss137s5Rlz z0bS>?9S@78zp+0*2)F-i5K^vLEK9^+uu0#!XpTMcb2#K%i|MKN*hlz;?SLS=?X96! z8KBpm@PqB-4jOQV$n+h^p6wj5N0-{$m(j(aS;G3ffVBybM+JG^X2v#|d%vtR9@H5j z$q;yFhy%a9SCIQP@~R+Dhj!WbE^($@JE~Pto1$4DN~JHCbI?nrN$21p#PXzF9blyn z;*N#MPHksXt0Fs!NU+!0*Q%()&Gxj7_7Urdgs7`Y^@W|f*IsyJ_ih;2p1xxDW22lw z{0~xpUm(5ys^rk6O8szY*_^pZ{CWZ1Vq>y1u*be4r>u>gQE1OtVP{MU<=5POt?jO{ zXBH0XhKz0(whgtaxqEF9nC@KwJ7ChB?9jmPE(jGf(rin1Hhuwozs}vB9Lnd!dH({M z?&0KJ_G8O9fx2oT@e1G*Hrk(HhVU|G);07zrfd!CVAo){Ie<wK;7n()b55&n_U%bi zoOQP&eb+*k{bCZ9sFAnrc_e*!AuI885^eW{WIvuH!RVQVTvFbf^ts)v)IPKH|4{cP z0CE-8{_ySYkaXA#gzZ6;urHF3$;Og}OeT|LGBcT;UM4dkNi&%x8JLZko=gH{fds(? z37fJAjfjG>7)2!n9t3@A6cK#viyB2V55xyy3!?Hrr|SHwZr8m%3<iDQ7jf#;sZ(dG zs#B-x-tOkVKRS<7nzPy02R+RY`}#<Vl{663^guLlBi#l>V-4JRJPpKyL+_-pv_HkI zE7q@%?Q>E57|MlW`?khb<j(KwThZ6o7wgMao=08YT*=AH=Z57fE2}CiD~TYs*F1Lr zYb$vketB3u-65RAC!*i4Wc$7`EWY#QDNOL(O3w4|8pgBdiIqDEzGql2wm+XT?_bF_ z-!qJ7-=nJO`@__I#v?0v#ontcKT`}h4^xwLo2vYnD)EEvJ#$gz<$Vj|2hra}Ppw}_ z|HVgE-dEXBdHJ#_l?!_t&TML!JAY~af>W!i&S;6haq{J{r5wxeTgmqSaoE^cBjt## zvBs&fBc}FH!wt&FpA6eZb*f&c=w2DNEnfLjWdrf0zb{puc|&!BGVF`Wu=j>h{>XNI zMpZA0$8&Mk;f>1mFI6r&bw0Jc+fP>iXS|Yz`*J$;kk9(naV@SE(QEzeudCzryIzb> z->^B>^Ypk4n~CU^es=7`@n|M;MT7buAvgE4$9@st^5&Gv*g?$e#(oNRk=Xyl=@O^! z970^7_`M#_<>epYF74;Z`F@<vQ_<K4MR3{hEwNoIScC5miM%i*dI}L-5vL7#_|D~| z#h&r{Ta`L1MV)80ocD+F1iE+?tMUF&9=MBFv7R>%WBhhCpf{@l-M*4H-w)`-9gSV6 z)c!z?poTA0^dBht3l+VFzp3!gDEv1SUc-M=_zepGH-*>mTMGXLg@0>UJ*D&Y`2{5L zyGr6?adm_F9aVWvsdAOT^|3qGXwpBa&eso9&3{yt@5OUh5|f|z^OD(2k)L9n>bE&w zua27hT^LcX{^LAqQlj?n$k^RH-DZiBtrxj_FHEG(leF;U+gzT1SgMV~EzuPw!+dz% zdcI_<?|6{}-PzG7Eav!e($ksc^G~m$YOM;`C&ouFZuoBWn1f?`j*YFD8rySfYz5yr zm2(jJvG+7R!}{yoMTEFt9oHWA;x{d7nBF`g-ba5{oIauI^y=u*2gZg+VtemAP90WP zjs0w9{f375@#$3+mHpo#WPKSm_>q@{B9EnHg%XyriMkC9ZP$d7e2F&byVt0jx#uY9 zoL>FJnSWRRiyg9UJe{}4{w%eaNN!%kG5$}H=!Qrnc`>KAm#yLL;J1<Z)A5nFJxKqL z&yYWgTwSO9m2%QEbFpK_Mq_lYTul!QqVyAm|ECusAM?3VKTjF>Wa*o$|KEHPR5;gZ z5$IDIopE{ICoYtEe^O-r%al1p;}7%S3jWhzpk*H!dXsz1{SqyNPjmRL+CpcRu?L<U z&FvRIvNE>ky!iffO*}TyaN+ueUzx5S39R6a>L5OH#bRf325^u%3<$`1PaRW?iyqB6 zQGzMP@kXCu?BwV%jGf2W$-E8BW9(F&Kh0w7RL0I?><>MabUmn6=np+kz#d%74L|iX zm;2Nilxin2&-*BSjnL2Dux8QN-Ky6w>8VIGmf~G!jCz2Y;%)xZ6ujB)ScX=Q0!lc= zP*4r+yb72=Jrz(*A~l8+EsY{YHEJg?mWZ}bhlqCL0IPqVikX{x^61>N$&PR7E2<|W zl%7)RcKO<QeZB#^OF8Yg?9Ev0tIB6o;RBqh@NRaQB72WMjnDqOMA5yc&i9w7mJh`1 z7pj&I)ScCZs^#K{9*_6cZPvvR9>Mq3<CxD!)DXVChTZ=82oK@gs$rvad0lm(8a<ec z#$I2uC3bxDSWdC!@cq*@Ja+d*)ZqP8v3V#`e=*VCxJD(-J3N{@^c?Ua&W>+T1n)+o zUx-8=J8=D!38nn(y_aM@9iMdOnG}c{7S=61J-(u0;pq#{NX4%#C|AcfsJbn6yRD<W z06#Of@*?WF_>{$GFmw&`I9;)h|NM&R(IaDr(=EX8_}I0ydtAbUH*^dArHcmsJCv?9 zxV%fDGGxP@Ysh7h*fSKhC&Z^#oqisje`EW!#y@)>J)W$jYr|OYO}~hD6L4WAgT$I1 zTyBZ&UH{Rm@#_oO^jt&-l34H4v3+x~o|`zDM26;uu2kigq4%$E$v2RO`ttqSD0>{R z8lN4j)tU6>=pSM$cCMe&Fr{HI<X?(z8w6tx4PT0Gi63#7PimM3LO2MPJSSQBzeLgX zQ}Tu8^P+IQ#kzhg8lU>+f|ujZQu`CD^;6or=z5B49Fp&fa!<g1Jcl;mHB7e)bkQA+ zp23UhJL;zEx#-4QX$IXiqiTKh$OHNss^SODX{ai>@}z~ay~bAZ$i~izk3PGtuIfyF z0qJseVt<`<;$y+(tNDWGt?15aRsFOZ>^wjAiFtIFU*FJB(Xb#sEx%sP40=Gn?BbK? z@}9fwP)`Q0ja{T*&Q}Porpn6~)JG4c1mtp+fSmaM!;5WmZ#!_N;lG~tWgWh>HatO= zw1m>$f$yn(7s&%&Svyz1gLvtr;9j~gAMxL_JB;mVL0w9l%*7g_uc8aCsO2)8XndF0 z9UYB)?@u@NO<kR>osH^+9hxYd0O5BiW0ND}PP&rjU39r@s$=M^$#u&7$8t%hG*umg zO}chl{O8onb)soq2sp)WvS{p1z93RyD6*C>Yl4hZ9Q6uir4;2{LG!z3sy#*bFCQ;q z?bFO}y34k9<2BEZJeiw@K0Wlx*elT-T^;q4ad)ofBl*vwxvTm1{=2LB-0)(QPP@G7 zzou`=e;ws(qOYyyRl7Z!yXrzp5k9w?W6HbgzWlQ)Anl@nMDNlFOuKI%JsgOwm^Y0N zS#&i-mq4-Ho%A+PY!$yI^S*k@zbm?N8tpA#r%=?MBJ3`8J9$}bYMv@P=_;FEAL4Cq zeN0{U{QUwBed}YnzPtM39P!^%^p_CgZmPX=fx6$@NSD$_Q2!Tf|Lb-CKdS!M$F`vV z?^XYsVq;bR-|GI~h}BnC#ixy77d(9dTYXP#3*Y+vLO*)`TXYMDwDrmbSH-s6zdm*_ zYx<<Ri@%E>Q&R+1*P^e`9p_`-wvm5~A56H1F5ndA;TT8mhtysAW2EW<ZP)OH+-)jC z{wB8Nj|=0+v9vEK(XYfPb9?Xn`q*LdseQ5L99_4Jt&Z)Ni*-yrFSbvPuKzBGoj5Nx zdupbka>a_iGy9e-Y>1t}8mM%8di1eK<eD#6U)Foq&-pRTJu3fwRAp)RsEqAVkF&gc z)U%rBz36Z0?XMT<n?V^9+n2AR-=;?((OC6Gr1~@7MX_&0HpZS_Q-9TovBhI!7e<JP z9|s5#56{;k7sU_Q@WB1?nG1VvrYRR0x|9CKhQ@2S$n&2u{HL!ye*b6le^NuWLp^56 zNB9+?-wDh|hP&x#8;iZBlJ^L`n8XkE8A}&1jHXG!Se0cEk`?*4AbryRK++#4o&K_h zo`{n+w?(3pBe8yR;2{^$Jp&mUx$4UJxP}K}`_KCv(S21t5c;18KlG)?W$Gc)gOv5f zucYT$w-D+cg?cig?wIaW)XzlXqYL_;=<mBR{!YVN#C=1<o3WOQey-pG>Q8HGp2!bI zp1wOaoIQK*8eYJ3G*DO6cd9FdXCgQ0j{HcDRGer#Zly0FAE+M-Z@MTpl^(S$i|xCU zo*huOxbbUref~1NDpz@7L+s#rWc#+*OJplg#2>2F^CMaxUs@Y2i8S0F>*Qm=y=z!D zsin?tTCL~km9R*|%dur!8r~w3`}K{;x@dG(L?xd8P%-DWXndZkKBKB7e73CN`S=rc zSlObUKR!&)*iPg4{uy;DeBX<2jL|h7pK{dQ=vyAW=l2->YAC-X@(3NWqu#5u&kXpI z2yff;g6hDR7xp#wkNz^PdhL|n>I}&*?2D%+y`a4_B)uS0kX{gIHe-SdH+0@p@#VAp zruqSA{OrxS@sSV2`=b9H8FAK>Y13lgU7L&b(usgh9P=6$_x07%YYX?sKCyFR?7Un% zU+urV;q>Vf=v8dKVt#?2oJL~bq%n)_Ss%+yjV0@2)9PboQ;D*DN?&E{P#%uMc^As4 zOYTq8JiT!Jv{=`j{~234HTJ2oG&Oo!W1aLMU~EI|+_Cq^md%U($cyKWsF-&0`e}#9 zj=AZ|_<_969*Ui_G5Wj6!Lbn+#m;Gs9~nDgUaV<e?2}_-3tMCRPmP}uKcKQ=+AY!P z`&3Su_WX79=fTy4AV~cIZp{?^@UwO3^S@$x{_~mdS1y=#3ln~3H9==HG@qec9?4fe zSGk~yd_ZQDvKd?XLGRx6vDQ0TDf)HGp>ckvzna@7Qqw0dioaErAG4t<{)?&yW9LPu zMyj5Vowv>Rhp=0!=)tGp6q}7hiRceiI~cp;`Y%>3`og-Zv#(!QwJ1#`y(C-pCds&Y zEerV_D{xeOtT8@z*%cMh;}57<5FJl{ZdU(Y3E<|r(@!VXQ9jQ_7hJJyZeIOofGaCn z;$KZD;n4>p`!m(fJBP+rL{~>*`|F%)X!I7<5NX{xG@2TDP2~%zm9zV%Rq^Y7QF{2O z3O<PT$0^~UTZmXc{~1m-ABGO<!=rOKX#N32GZ@9>J7Y)0b0arY#!vt2K@YGlU%mf> z$|=#wBQK{XCqGsHyQA_B`rdpJs4l#s%l2cKk1)|G^iXf;XXx}D-IJCuy)=<+THe^% z+0yPcx2(u^_H}sKuJ-0^S8Ho;OU}z?)dxA+I<wt<^qG@vwwvy^bFI|poWeF@(&J?- zYO=kJD_XMr^_X1g?`g~F8Vga}dzW|h<mf9rb6!VddwW-t*V}ep3olO3r%Sf2H`~>h zBbg+nX}OOVe;aYOwY_m!uf2(HZduy5EKBOQHML|Lb4)?9>1&L$OB;JzJjN)|j)2}K zQmLiArK5$E;U4_Li&C8lh2652T$ZzI;lhy9ssx_AysM+-<Xls3Onc+fu8Aj8?~{91 z_2gPQ2-%+PZRzc8qqp40k1IKK%(#-1aV!{PUiKMNy`XH&gp*5?Wpht1ot3OppU_!Y zMz6qYzjSrxT2|(=td7>KH`~<JM~a7NQ=|#w+}_o>Y_$5rqd>oW&m)lab0TCjy$A1Q zoBDc4OnYBPr<d($>^Y~Uhvq<c7yaqwZ;587&90~__bZ{i&7P$9je6Ubb+$B*)^j7< z-Pk;lIP(`sJ4%aY(Az3#SSU@^)M2@E=4VEiji!${jh#4pOb5RRMMZCK%fzuI3g~T_ zKxMA4vt`<{md=)*wk9U)X<9ywK1wxaGId%udQ1&<qL@F8K2UYqX`{!qc6L#fNONNv z+uIs@>9Yfb?Cb35YHuIY-qqFJOVvb08U3Z>VbeKdx_i2EEls&DJ=?T*^jPWjq{fQ9 z0kha>v6Sa`OK0QK_Lk;A7d6}L;!#sL+t=CG+tNJVo%3MVPM^oJQ<&F?<KZ^F9(hgh z+T?y(uy0-|!Od;G-R+I5vMU<f`&tS<b3z|WGxHXo9aARxSm>!qgG^&xqKommnBZk+ zc6GJu%A^9L?TqoUb1mi1YtU5eY;9ZSHo*yMA!f6!9XzQieodYzlNtoPc*qet0u@dz zB59*J&fTb!3LiAaecd{O&@`dej+PD;5>@mevk)=#2(8HRaGJPDjVcoA#@05P^<6rK zkY@|bXRVa#tvxL*oP|)}Q_Lwip2Nz}XJBYOb$C51v&%?Jh-g~g*`Doh$}Vkc@5$!6 z80^h;b$j}AHfk_ILN^Fa=d?5n)l#;iy0kt!w<eX&rW+FFUT&q*vzy+vYof_PjC+^S zTxnU6%QkVOUX^WZZth_X)YXWWNhK56nd8Te%g!pVV>Ic0u9qXADc9c9(zGH=E2qih z>DIC8oUTra7@{8QKtGY(*VE}$SIqaRV0W5qmOS0my-IB|M9U7-BR`wn$RSu)`+8ck zJw1J-eYUk*{ben>8++*0VF@xAdNs%NZbZ9|N8235<a4uhq0&VmjTkUSh<m-N>Qri0 zQrU(`tv(n;UN~j^X(b+|wtBPZZfxrjf064k8Xj$uD>S;lr)AlAwpk6$@~+-omiIau zR&iD@El2IF=DzOsmX+C#u4Zm7udlACuF)#wx>{-KbhX)u-?Us!8QNd7WKOneDb1Tk z+HGi+^H9(>rec`a+RSfHdfIT=(e&Mt=NC77)-20gjj)<`og7H$+qK!59W;G-_9?xU zFs(HW`HHUgT;sBqaao!HD>*!~v)h*T<y!cgxoP^2H!;6pIC$c#g~20AWV8!;UEMUm zZ9Um$@~fT5tU#_;?dWZt%`Gdf1RbXOXnQ!7R8})Lx3aUjtFr}jS4{^sX*wG90`gkB zmo*YK&sH6($8lKbR*}&n$1~C$e%_Y7O!=%8<JHiR)~hIupdskxO-nOXZX!NQ`+4DX zQ@YaxfFrN0T3Up9UeLIa_3UcjC*Ft?P0HTJ4w@6$p2pk&q1b%%uX{O#ZHxttl+j(@ zXKkbp`Eu~^T5~P521sHveK3!8ZppPa<-EeQL)q6$8yw{=9gR6k!VEv2Av{OP`Vuv? z+9;apC2SInX}by^YyvsmYdbgFv$Cg!9o51(IH-e^T-M#&+@+#XayE<9@rb-vuprwg z<Lv6_CLX<{Z3k_<;#Xg#nOVbrA6%kVdmqi49{S{CKQU0@LT1`HBzie-e$D*yY&t<R zys@*FhYd?rnMbp=qj#AKhrIlG_|!t{?xM-pLK|*xHn&n@LEAE##?6YBy0vt!5T2Ah zx3sqOv~)I62;+&+-PPUH*3)#ZA|>^8O2>iG?~R#NrL)R4f|7L3bvZ~7&$eY8k7@ph z8&r^X4D%ZMa{P%>_K1JFbNsO*O4jhG^m+x8h<75}O)UsYLR)$|iCu4}J_?XKdCmL6 zi4GCqsKbPf?i7AHDY&Z`+Q})c%rURMYZ*<Z6?70`9U9wnGL|KL5>O#E+uWFIq>iFN zliDDAyZU-4?I%TbfXLZ-s^>k8R<4c0Aw?IqSq+-nojBVd)oDP;2JxvH6*GZ(HmeBk znaJ(6<d#!*)6>|YCK5Z1WUDa5QOY=9?@-jl!G>2DxAMNAj3B&TGrVWh04hOEG(Kvd zrcgwddbzF~?|eK@IH0LHVnVB4lDvzjlcn=h3B7J;rR7%kE^lkqX#=G&#PghNYh#-l ze_pt~v{ldu&=0Wa=+c{|4-V6&!9keZ!|RpZ#QT*VIwLYUOGn$n;Tflfhr8%qM!A-s z&-8Y;G<juZ97XktQp-t&Zk=hW&jV{alBF4y3h)`!W-iQy#$FqaZ!IVYW}O~~{*uY? zr*&o{{Qv<?-CS2!mLsz#vy7SZNbnNovGUrwC}YX05Ke<FwGN$?%ZBOX4)o-uyPI~y z=8i^+fH)qLQ`x84EGtdw*cOVCvQ&61*vI~`PE}czCG07cSk+IkiIp+H5>8-3(hcEB z4Hqpp&cXDM`SNHLsKk*hTTNIpw{2-wC9FIf=s&Mjd1HAa9ad;hTt=CM2@d>`XbKgl zO&WhHyHvDqY+ljGaZI8RC7u)r__$3%5QVdC{&+$Lc7~}y-m31RM1`ErOPd06Q(Fhk zS=y3ls7wOMMg>Qtr?H>+p`Io+YdNJ*lU)0O49j&<!p}v!O&Zh;v+J1T^DI)wh4S>= z^5pz-N{bV+LTMuL>f|Jw;y<N0bV)*!$)oF$7B!kWW>YL`Y|qj@rI_0=(7Mc9x~f}m zd1_eXaA+r$-gh{UP9|j)@ZQ(6G}}y3HrK<`wTTMM6LyqNka;wC4`uQ$`fR=4-psi1 z6cI5dOVs<h($T;CbGbIpA5N7sO=haYChvGY-_m|Zk0ATV=$@6!`_-22=h#iLhmILW z8SY6}CwjGYuWIe->Yx*?J-F~LrZQL1bg1JB?Gzv_<fW2!%CLB^^hZF-cyZ#eJC|Bo zz8xx?ri9lvs|96-OvSDoWnMhgJklxxWBjotlxQ>^AXIqbctQ@O>F-P8Xkw}-wiJPy z8aa=meW16mJ?ABo74y>thd?z>YHQ+Xr6QJbomzhqBq$f8#aaAZ?*GuFZ^5)u+Kl<* zbx?LqSzxNNBEj=Zoq-6cPAFXPP(YlTDOMAXZM?>mk0`!tPX2JCB<W?U4D_$qLi^}$ zi83MI6j63|v^4hexsD~+5m!yZN_#*JirS>qwd6Tupt?!yqJ);Rn4T^^S?~dr>b%#{ z^rP_8N=H^26?tiZzI1}mV`{QDHa9j==GsapHO>?i{rE}ac(^GV3yFMjj@sym4W}<u zsH}vt5ALI{NLyC;gdks0(g@$xPd8GeVatl9?mk+}6utNfKi{l&(RJx6dUc{_B~4EM zg&buq%T(s#_h}RPlM-P`VR(_6fiiK>(;ws07YwGkcX=OOGxSqjQKu1|xN~Mr2S@A` zdN;>BFtbuQhW96O%p~PZzL}ykbjZ@CD_RQZot=#wvaHuT=wwLSh@Su226`X5kroDD z@bERK9eCO8)fb3xBFEn9<~-Fu=h#{be|*ELBBe(o&a;4GV^<I5-Yc8h&(XLXe{m9p z%L>le`+D13TDrvtxJRM5LY;eaE!}1s(M_O?ZGn%~dMUuL|KJA>U%ejBaXrdCd>P%@ z+~3xmTh5y|UsWrE^bnZbk9*M?YRh64sE=Wi*_`Zpog89&$J5!3mIn<5&1}qNOk<g& z)X3)oHIWnxNm|M8AxP@1iDW8rehXB~N^(1^>ZnAanU@L$LJjam--?pS%iHK;|7`Yq zkM=vw%axR4>vg4?(1SX3jGr{QjY^tBH1^GOhLZ76+b*vrN>!H8>0fN1OoivWr@q6+ z*sh|dUN3qzsO#&Vu2pjLfmuw^js{bo|8=y+vNcga+(&^L+ntf3=WR~bXJJU-OI0=9 zWQb@6H>=aCf6v!9zWyc5%No%{=MgHTH8!2w*VaqN7MjrNvO=jNtobb9al%T^PW;?$ zMxioZwTA@S)e@&0M!Kq0^MKqXGlHRlkYoATFhN&Ybbe5`5^}3e>&XAbL<N_`dht@K zNl$4x-pSq~Gn-ZiM<2VfasXOEX7ehh7O#If9fD}$^WC<LzZwEsA1&>2lcJ`%Qi=n7 zZ(ldZB#rbt(Tx`Lbfc-KjaHG!vUe8Di|(2`RzV~!U$q<b^_ECEUXO|1V>mcq&YHtq zueXe|#zs1Juv&aiO5t++_(}8>g=akFtBq~hmhQHa$z)&)S;&eI!)6MU2nc*lYb>L_ zip8XH1!GRP^?d8BVphva+K_XsKIhLW-%v?3J)q$9b^?tZPhCpN3W63(QMb2{i%nHc z6|5YYGVDhh&z{DfRVoia)TNNRpsS~uLRV{hU+;3Sy^#|O`uKQZpyr24yed1FuA&{C z5=ZSxb@V_?Y}SYA3H+?1xrYk10G4%=WLA}T2zn&L8{&seJo~a;lS+}9QLjfY9dtDI zo<of3G|Ra`iBAIS43T_|?Q7yq#xLBeh0V5)EF!H|P%P-`;VrL_gp)26dYMQyshLel zNtZ*Z0;l4o$e2Q}f<lIBU(+JBCE_c-Quc9F@r8`yQv#1M?{L}WbZcUFS)Qeo&ihg? ze(upmXQ~c*Qq|1Qmgt7vKKZ5WWI3(Mu4TMU*sMZvQDii4IWJN3fIUHbfbBp``P9PK zu`~oMqocWT72W?(P*Z6iVL0#pkhr3hrpRI#>jy4$AJf#!`4>*+tvbLuYN`#530XWX zJ|7o)q}L+PzZBNBP(9ZXF=|9iB+y)R?n)*q^Ed_27?RY_hElnTOUfHt3e#LY4nF?0 zGP^pm=c&L#Yl#%4?7^{wr=Lm(Og=6{#e$Y~(8B||k;m<cmcU&MQ)Q##z?&dR<Nd|y zpa+#qQrAPIe+xbBr({vF^Z8C?G)`YhQ_0u%w%;M~&pa=iD$7=t*OgaI$d;9s%`MNS zDi)S2EFGG%bmK*LIsDw3$f`>diSk+M5p+r+%H~#7%~CYnTvk<?O_x>j(;~zSH6+}Y zs+d!oDbJJ};`H2PdFiZdvSwz6o{G^4ttMMBpDqI`(uy;k&nwEx>6xFW5)%E+05qK_ znwF+gHD$6(@WM3G=GDy1metHpCu^!i&(frooTP94ED)BcsK^qh%5p8cY%Wt*%=bDt z3FPNjI!&Wt<lRY`Q(8xksF<bQkkUQKRn)F;fJ_#nheLHLP0q1OR8*JOWYTaW37jdG zmy#!{DpF}G*!jxuGiik8o2s}@`7DvFNtc&tz1a*JGj*Y&`WeESvhq|an<Bf)XXzH@ zgZZV^c0gzrl+K@%O=S{^nq-=CgQgX9iXfL0TUD}RO6IKcs&uK*rn<bkCfPtON|6fs z=0xsPlL#uT)k&G2JORp+*#$J_R8-Lbh&$8NQmx_Y+Co;dD`wXy0Wv{SiSn|F*%f69 zH$GdIt)s7Xg%Tli%<r$6W!YI3)kYnmE={MC*;Kl;tg>|0tfb;wcS^RRDnUDX&Ft9} z+1bAF*~H8g>s*>H=LOO{Q{QZJn_5jJ*;#ryRaML{H%p4HPH67YYNMq^Z*q{`irf4u z<$R2H-Q;Xlg6_vi9R2Jbvm}D*)Eu<)K-Z)yXu-(@5{VUBqFxr<&2dszq%AB@YA4pK zVX9Be(MFl-1SQl|wGNr88k!%_K{uAqpPQ{HIaQCjiWjtOw0|=6oSUIU=^Sf6zrB)8 zHKfwz)oO<Myf(gI=#u5xS(${9RuG`9edDvUX|AeAXXb&Ex*uY}6*YCLKfOQGMi+N2 z^!^hcZE$nPdnUzGI<+ye41QT6lctraP+HCGtkQJp%+iz?<6C0cS#y%5)rwS^#S^$< z{v3~9LZXXl;wfQ)Ji<Pp<ySFVFVu`)+oYhP^H15rxuY%RG>%`Cpr=r@&vJ<2j7p10 z(0!a;IT?g(7N0C#AW=;(C0Tx|pO~8}on4-tota-o(PqA;T2PamWnxjXd`@|NLiH$3 zHOw!Yo2;2%lSy${W(gej%Bo1oY(XT^QzKv%_7}4t+=K(4@n|YgkyoOM#%AE?6$$m+ zgjLY8GV?2Rq@;C{F0W5xlKLYet!WM`iZ?AVv!G{I%u%>G<>@)eEG>Q7{>;4duY3@u z%4r{*Tazr;4pSqB9my>8>P%I-f`cMQUd4aDRBDo`Y|Z?t`ChNi@Khsz8+CS0vL=(z z#N$<HsVbjUK3lc3&x}%uxeY13tW=wJ0og_pF?B2E%rC9dtmwOJYtl9ID|mmV8LGM@ z)3hHOeron|*sGYCNsCoJg(PZdG4*Acf_2Isu21U?qEHc8Qd)`nnW;(E<q|_xJi)eC zNWs3wO$*<#(#vh~JlVHwc`5j)a%z`W&kD6q&92N7B~c;qh+n{=oJH?iH8bbY?x}UG zs+mKJsbD6{GN~*lhht8a&Z?_O@s3w9pSB{(v^nFnQH9^%p?uv&ma>|vs_cUDiaB%B zmI)%bo{qe4@dF9g(}_CbeE+^tpkXF8mja;D&1B$oXGc%R=pd}#8YP|;i8?y?5}@8d zD(FvpAgv1uTgE=InRj~Hm>a0u-11o&nt*fYq^kmvVl_UST40pM<l{6?PdvXezLN|q zp+>qYK|{<N99EUyP)p0oYBKZFER0D-ms#bcW2P)!lgx6eP->%<_6v=iZ-V&40}Zp8 z^x|{Hm{OS123{^UEtI_^nb8{<t$cS6_AOvaF7?8+?k9CQL&7wfS(;2%P%fgxsW@uZ zjh)yzzVFX=>g_@W5}FDs2{%EKADi$5V|VBT&YipZu%K^=_!QWhUCtMybRy&1*XE`4 zn4ey!RH<oWE8lg}owsis3i1qPwKFmlQz>(WT`3wH+Qa>kt+XyQBBkc)*^Rx1(#q0V z6ox3&(cYj9N@bJf3Ce9G(Irvy8TOwb<N`s_>q$~gA(b{%&7r(HJD(!5U0P|g@w1UK zjVY#6x~_LEfAE(`q_+m6MtWhv8qrc|8I)BfYG{Y`y1UxjnzR$?Cj=Jg2_sXDw%z%n z8?UXhQgRlX#4j$<>y%1qJ!@&D8;Pj~nx{23-=S&1hY*_V+J~vR<@7>38#J3@*PLpd zN9cfCmTXAqx+D*h2AV0v-3qh&f~cZGy-rCn4(`gJTvrK4dequR53zNO%hJ7{9*L0g zRXYw1cohX%B<1w9mvRi1DY0S&+h>8wlv&qTNNnSgMABO$@tTeX>No<WX%=MbN~`>5 zOkUtx^8{xppq$OQj8<Byroc4Cx`JU(P~cWAGT&&+P4VnkxPry1(=@h*hMaRnBdLJQ zBnOmJC9`xYu*M;|!aSAN-0Z>AJg!oi4<ZPiNU@|jiqI=P^wN+V*7fAjGg~$|KINNp ziP1)fFv?PCFXO8$wnI;Oo~Jrtn6GmaW0yLi_~L}#aI9xavN8#cl=9k4MIEIe{&BEr zb;xEzn>$@V@?Hw1$osz3jPkX_0ykgNMpu>3DJ^SI+W2;}f+N3Lg8J4@J%F+xKgE&l zyVoWY6q!=xCa>fTduGM_S$+}r+^B4(IIFH~=~qN3!uNG7rJH*d?fLxzz96Re0qFuL zOYdx|clsFcde3R&x2`+*x`Qrv=>=sD=vn$CgL*2&Pq5T$G<=#VxUb{SRdu$VtP8&W z*H4)hKh}Uh%1oD}t@<g9dap=HZEc}<UFjWYYNqp8KR?xNZ=tuD@b8lXM7#{ZvkYnp zz!Lh20sa^BuGq9zgTcRN2`cK1%L6{ZcHCUF;{;zvz^4c<;w1orXT(bZ^y&3Lfc*+# zaj9hm@K*Kxqx6wGuMVJ3)0+dVt`-)r(#OO3AN^L(i4SNnuM7M4KLrG1pA2*-HwI;( z-_O*C&iO-u<BIZrL}V}x;Ku|<9s~Hiu!?w#tbQ7LTo6!+EJ_u#XoPs{FyplZz>NmA z#FcQU2p?^fNB}&+pfUg_8dNR7dV{KSc^@reo248=BQhipkH1`ig&tt1Y1az#|CCZ= zKTHn$+m*sNR|ex;35;|3mpXRPC|re6cu3k{jlXS@XbqeEZPz=N`P*FiPYEq%LDVY= z=;+dfPF@flMxXWMe{3vZFsF{Uuhq@=FFO8NG~tebUl$zBXn^1u@fHL0vA;9Gexm48 zBPFo{h<+4KtU4Nc!*L6_a21BdrL7ar3#|lzr_rZm`Cr7#YQX+&6zUe+3*a%PS76$2 z6zZpK7@8qrBRFghZHSpqIV52-6f`dhEz<!0li<jy0HGO;k2O|9I~-}`)LV)<6+Ree ze31aS&Y%MBq2Fjz|LDh%)j!e;ApPW-pfUjIR}ckN3$W3k7U?$o7h~Bk;&r_EuGHQv zz(NnO)3jd@=5SGX#Bt@Yzg;Peb7e5jmB2V_friqeDeRz8*o;wl)Un3jHeIxbP5!pq z9LxM|u6)$7qf*`huu>+-5bw=MCZISvUMoPvO9Nafkuu^f0XWRZE1gGejG3@Y0Q!Zd z2O+c;LeY_;+O8fb=a%D*vPpoCOKhQjulJzxYZK{G0DteNg8{R}0M*$QhB`Eic=Z79 zHF~4~`t;us&>za)D*bpS0lvfVN&tk{Nv*9t&=nq5Na%)gAOV*eXJo+(c85gLDq;Do z^kP*3!<Q8M0K%<I2JXj-R~ZM`r~T_as6Y)Sge54u1$ay*BhvtWLU3`f+l!ArdfW+l zV4zmqTP-cXgeeL=m^WbPWH~@1l+X;LM6nr`gGorZ#yojX*pLr{y#hNYWW6T6SX03I zH^4ml)i8L$Wf<nyH-r=X!eKKSuwG+fF-o^@nBNAH3EPLzv8OkW+QVjkrT|*ym=IpY z(1dKglVnENj)S+#?K@bj+<tU032GYHRA)GvQgFW(IfvWb--a<j>GJs~<A}a+H#rob zb>JX9f23p2N72LWJ6O-7--#ld=Tm<kHH-^wg#cj{#m?=4=%bKuD@uf#-;0QlBOge> zoVH7M00{+#DBWIzR|%?Ed5ePb0*MxSy<>g#c#qs7Kqt=wmE}E{x%^34x#P_W4ovrr z(sZ>UsRekGL1nEX8VdGG7bCG;0<zHrqi8u@f~DrN3&|WloFpI-T%IweWdK468t-6! z;|6Zh^wI~l{J_TOj(K>fcBzQts$#agv=qo(+Y_>-|BuP|G5|+OmP<hd;2ko*!ZT0s zdd=`k1AJC^k(0Lept8)zEuBa0GJ6xYwFecy;9&L{6kH3z=omUW=y$PEI0<l^)#CLY zRHg}%JOXg0pAIH`!;dWHacD@{C%_@b<4XYg^bcmAQ1*S%pTjKR4~$I-fKS*#*wzDG z;bC&nwm^Cd0mG#y3jjRAD4PI?fu-!zWgn7|4#a$iIbbdUCpa}E^ybCZQ^oJBCSVLy z$e1x1xPQji6|m1WubY_&HMp}ow9v!)VKMlFS4aYh#noUOnhN#`B#@9*?Hd}vX9><G zkS@c4v_DyV&oqE12+nc@2L82aH85BjemBDni~|ghS`MyXYsDUL){)WeA098=zG0FX zS4<{GMW?o?9U;?&W)(oI94A<=azyA#xMnx3a{CU}Dz_i)2tiE)o5anIrvCKR?e1@L zEq3{QlyO8~xO;azf01L)N72LWJ6O-7-{(ZOPHj=cxKL^f5c7!w^Y%dWQApRlSgbQm z@C+o4AOUj<%kBV%L~6I!;8lVuR^FnZynvSIRVRj!uR>B=P+8uCnait%=at4uf$9Fb zG`(d=Y61SkpaS`SuvZ|p1&QSnkc}o7Ma!vZY8#T4xKkoX5|9XzQ%p$90E7}W-oez? z-BL)?qN%Mr=Ha2*r6P_+Q(KodB(>cn2K~eu2JjI<h3Bzu$EeqLJbM1zFiW_;eq5UV zXh<>uUmZ}M+mYp==PQO;K;G-pbO8N!J^!QF0kG>JjiP~jyi<erFZ%VHerbT$(AU26 zKZ*eWPqwT!ccRiDNTLJi6S+Ac@;DJyI#TnGdBfk$qf#bFj--HB`w71(m9vd1)LS#M ze<9-TJvENG0lsoCjic1@Y2o$0Pv~I>=;jlpB(iTDs8K(ZlDX{=c$lccI5-5VF;4fi ze@n!8IGLWd0Q`z5OXIYu(^X9&T}2eq)kGm(RTR={p`kNHmwyb`b=DW~fuaoQ2e99u zLLKKS_hDYbTwyxE@El1krtDnbkOHnUnk4}KuR	SF*t1C}%&a{?L`#6;rmvr!3%U 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%0DRn_Qf~k>UojC-YJ@Z$W=JvsCmB=<;1GFfIb11F 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 literal 0 HcmV?d00001 diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c index d74b1c6d4f..c0a3e8a720 100644 --- a/targets/ARCH/COMMON/common_lib.c +++ b/targets/ARCH/COMMON/common_lib.c @@ -60,6 +60,12 @@ case USRP_X300_DEV: case NONE_DEV: printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); break; + case ADRV9371_ZC706_DEV: + printf("[%s] has loaded ADRV9371_ZC706 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); + break; + case UEDv2_DEV: + printf("[%s] has loaded UEDv2 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); + break; default: printf("[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU")); return -1; diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index 433e29e97d..7460c4849b 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -97,6 +97,10 @@ typedef enum { LMSSDR_DEV, /*!\brief device is NONE*/ NONE_DEV, + /*!\brief device is ADRV9371_ZC706 */ + ADRV9371_ZC706_DEV, + /*!\brief device is UEDv2 */ + UEDv2_DEV, MAX_RF_DEV_TYPE } dev_type_t; @@ -216,6 +220,14 @@ typedef struct { unsigned int sf_write_delay; // write delay in replay mode unsigned int eth_mtu; // ethernet MTU #endif + + //! number of samples per tti + unsigned int samples_per_tti; + //! the sample rate for receive. + double rx_sample_rate; + //! the sample rate for transmit. + double tx_sample_rate; + } openair0_config_t; /*! \brief RF mapping */ diff --git a/targets/COMMON/openairinterface5g_limits.h b/targets/COMMON/openairinterface5g_limits.h index 98de4a024f..4ce85f4cad 100644 --- a/targets/COMMON/openairinterface5g_limits.h +++ b/targets/COMMON/openairinterface5g_limits.h @@ -1,7 +1,7 @@ #ifndef OPENAIRINTERFACE5G_LIMITS_H_ #define OPENAIRINTERFACE5G_LIMITS_H_ -#if defined(CBMIMO1) || defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_LMSSDR) +#if defined(CBMIMO1) || defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706) # define NUMBER_OF_eNB_MAX 1 # define NUMBER_OF_RU_MAX 2 # define NUMBER_OF_UE_MAX 16 diff --git a/targets/RT/USER/lte-hwlat.c b/targets/RT/USER/lte-hwlat.c new file mode 100755 index 0000000000..9f5a3306aa --- /dev/null +++ b/targets/RT/USER/lte-hwlat.c @@ -0,0 +1,944 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <syscall.h> +#include <sys/sysinfo.h> + +#include "assertions.h" +#include "PHY/types.h" + +#include "PHY/defs.h" + +#include <sys/time.h> +#define GET_TIME_INIT(num) struct timeval _timers[num] +#define GET_TIME_VAL(num) gettimeofday(&_timers[num], NULL) +#define TIME_VAL_TO_MS(num) (((double)_timers[num].tv_sec*1000.0) + ((double)_timers[num].tv_usec/1000.0)) + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" + +#include "PHY/extern.h" +#include "SCHED/extern.h" +#include "LAYER2/MAC/extern.h" +#include "LAYER2/MAC/proto.h" + +#define RIFFA_CHANNEL_TESTER 0 +#define RIFFA_CHANNEL_TESTER2 0 +#define RIFFA_CHANNEL_DATA1 1 + +volatile int oai_exit = 0; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +#if 0 +#define NB_ANTENNAS_RX 4 + +#define DevAssert(cOND) _Assert_(cOND, _Assert_Exit_, "") +#define malloc16(x) memalign(16,x) + +#ifdef 0 +static inline void* malloc16_clear( size_t size ) +{ +#ifdef __AVX2__ + void* ptr = memalign(32, size); +#else + void* ptr = memalign(16, size); +#endif + if(ptr) + memset( ptr, 0, size ); + return ptr; +} +#endif + +#endif + +typedef struct latency_stat { + uint64_t counter; + + uint64_t stat250; + uint64_t stat500; + uint64_t stat600; + uint64_t stat700; + uint64_t stat800; + + uint64_t stat1300; + uint64_t stat1500; + uint64_t stat2000; + uint64_t stat2500; + uint64_t stat3000; + + uint64_t stat880; + uint64_t stat960; + uint64_t stat1040; + uint64_t stat1120; + uint64_t stat1200; +} latency_stat_t; + + +typedef struct timing_stats { + char *name; + double min; + double max; + double total; + unsigned int count; +} timing_stats_t; + + +//static struct timespec get_timespec_diff( +// struct timespec *start, +// struct timespec *stop ) +//{ +// struct timespec result; +// +// if ( ( stop->tv_nsec - start->tv_nsec ) < 0 ) { +// result.tv_sec = stop->tv_sec - start->tv_sec - 1; +// result.tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; +// } +// else { +// result.tv_sec = stop->tv_sec - start->tv_sec; +// result.tv_nsec = stop->tv_nsec - start->tv_nsec; +// } +// +// return result; +//} + + +//static void measure_time ( +// openair0_device *rf_device, +// struct timespec *start, +// struct timespec *stop, +// timing_stats_t *stats, +// boolean_t START, +// uint8_t PRINT_INTERVAL ) +//{ +// if ( START ) { +// clock_gettime( CLOCK_MONOTONIC, start ); +// } +// else { +// clock_gettime( CLOCK_MONOTONIC, stop ); +// +// struct timespec diff; +// double current = 0; +//// boolean_t show_stats = false; +// +// diff = get_timespec_diff( start, stop ); +// current = (double)diff.tv_sec * 1000000 + (double)diff.tv_nsec / 1000; +// +// if ( current > stats->max ) { +// stats->max = current; +//// show_stats = true; +// } +// if ( stats->min == 0 || current < stats->min ) { +// stats->min = current; +//// show_stats = true; +// } +// stats->total += current; +// +//// if ( show_stats ) { +//// rf_device.trx_get_stats_func( &rf_device ); +//// } +// +//// if ( stats->count % PRINT_INTERVAL == 0 ) { +//// double avg = stats->total / ( stats->count + 1 ); +//// printf( "[%s][%d] Current : %.2lf µs, Min : %.2lf µs, Max : %.2lf µs, Avg : %.2lf µs\n", +//// stats->count, stats->name, current, stats->min, stats->max, avg ); +//// } +// +// stats->count++; +// } +//} +int32_t **rxdata; +int32_t **txdata; + +int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg); + +static inline void saif_meas(int frame_rx, int subframe_rx) { + static latency_stat_t __thread latency_stat; + static struct timespec __thread last= {0}; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC_RAW, &now); + if ( last.tv_sec ) { + uint64_t diffTime = ((uint64_t)now.tv_sec *1000 *1000 *1000 + now.tv_nsec) - + ((uint64_t)last.tv_sec *1000 *1000 *1000 + last.tv_nsec); + diffTime/=1000; + latency_stat.counter++; + + if ( diffTime <= 800 ) { + if (diffTime < 250 ) + latency_stat.stat250++; + else if (diffTime < 500 ) + latency_stat.stat500++; + else if (diffTime < 600 ) + latency_stat.stat600++; + else if (diffTime < 700 ) + latency_stat.stat700++; + else + latency_stat.stat800++; + } + else if ( diffTime > 1200 ) { + if (diffTime < 1500 ) + latency_stat.stat1300++; + else if ( diffTime < 2000 ) + latency_stat.stat1500++; + else if ( diffTime < 2500 ) + latency_stat.stat2000++; + else if ( diffTime < 3000 ) + latency_stat.stat2500++; + else + latency_stat.stat3000++; + } + else + if (diffTime <= 880 ) + latency_stat.stat880++; + else if (diffTime <= 960 ) + latency_stat.stat960++; + else if (diffTime <= 1040 ) + latency_stat.stat1040++; + else if (diffTime < 1120 ) + latency_stat.stat1120++; + else + latency_stat.stat1200++; + + + if ( (diffTime>=1500) || ( !(frame_rx%1024) && subframe_rx == 0 ) ) { + time_t current=time(NULL); + printf("\n"); + printf("%.2f Period stats cnt=%7.7ld 0.. 250=%7.7ld 250.. 500=%7.7ld 500.. 600=%7.7ld 600.. 700=%7.7ld 700.. 800=%7.7ld - (frame_rx=%d) - %s", + now.tv_sec+(double)now.tv_nsec/1e9, + latency_stat.counter, + latency_stat.stat250, latency_stat.stat500, + latency_stat.stat600, latency_stat.stat700, + latency_stat.stat800, + frame_rx, + ctime(¤t)); + printf("%.2f Period stats cnt=%7.7ld 800.. 880=%7.7ld 880.. 960=%7.7ld 960..1040=%7.7ld 1040..1120=%7.7ld 1120..1200=%7.7ld - (frame_rx=%d) - %s", + now.tv_sec+(double)now.tv_nsec/1e9, + latency_stat.counter, + latency_stat.stat880, latency_stat.stat960, + latency_stat.stat1040, latency_stat.stat1120, + latency_stat.stat1200, + frame_rx, + ctime(¤t)); + printf("%.2f Period stats cnt=%7.7ld 1200..1300=%7.7ld 1300..1500=%7.7ld 1500..2000=%7.7ld 2000..2500=%7.7ld >3000=%7.7ld - (frame_rx=%d) - %s", + now.tv_sec+(double)now.tv_nsec/1e9, + latency_stat.counter, + latency_stat.stat1300, latency_stat.stat1500, + latency_stat.stat2000, latency_stat.stat2500, + latency_stat.stat3000, + frame_rx, + ctime(¤t)); + fflush(stdout); + } + } + last=now; +} +/* End of Changed by SYRTEM */ + +void exit_fun(const char* s) +{ + + if (s != NULL) { + printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); + } + + oai_exit = 1; + +} + + +void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, char * name) { + +#ifdef DEADLINE_SCHEDULER + if (sched_runtime!=0) { + struct sched_attr attr= {0}; + attr.size = sizeof(attr); + // This creates a .5 ms fpga_recv_cnt reservation + attr.sched_policy = SCHED_DEADLINE; + attr.sched_runtime = sched_runtime; + attr.sched_deadline = sched_deadline; + attr.sched_period = 0; + AssertFatal(sched_setattr(0, &attr, 0) == 0, + "[SCHED] main eNB thread: sched_setattr failed %s \n",perror(errno)); + LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n", + (unsigned long)gettid(), sched_getcpu()); + } + +#else +#ifdef CPU_AFFINITY + if (get_nprocs() >2) { + for (j = 1; j < get_nprocs(); j++) + CPU_SET(j, &cpuset); + } + AssertFatal( 0 == pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset)==0,""); +#endif + struct sched_param sp; + sp.sched_priority = sched_fifo; + AssertFatal(pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp)==0, + "Can't set thread priority, Are you root?\n"); +#endif + + // Lock memory from swapping. This is a process wide call (not constraint to this thread). + mlockall(MCL_CURRENT | MCL_FUTURE); + pthread_setname_np( pthread_self(), name ); + +} + + +int main(void) +{ + int ret; + uint64_t i; + openair0_device rf_device; + openair0_timestamp timestamp = 0; + + int sub_frame = 0; + unsigned int frame_rx = 0; + + unsigned int nb_antennas_tx = 1; + unsigned int nb_antennas_rx = 1; + + + openair0_cfg[0].mmapped_dma = 0; + openair0_cfg[0].configFilename = NULL; + openair0_cfg[0].duplex_mode = duplex_mode_FDD; + + uint32_t **sendbuff = NULL; + uint32_t **recvbuff = NULL; + uint32_t expected_value = 0; + uint32_t received_value = 0; + int nsamp = 0; // 1 ms + int antenna_id = 1; + int c = 0; + int numIter = 0; + int fpga_loop = 0; +#if RIFFA_CHANNEL_DATA1 + uint64_t first_ts = 0; + uint8_t is_first_ts = 0; + uint64_t trx_read_cnt = 0; + uint32_t j = 0; + uint32_t err_cnt = 0; +#else + int failure = 0; +#endif +#if 0 // 5MHz BW + unsigned int nb_sample_per_tti = 7680; + openair0_cfg[0].sample_rate = 7.68e6; + openair0_cfg[0].samples_per_frame = nb_sample_per_tti*10; + openair0_cfg[0].rx_bw = 2.5e6; + openair0_cfg[0].tx_bw = 2.5e6; + openair0_cfg[0].num_rb_dl = 25; +#endif + +#if 0 // 10MHz BW + unsigned int nb_sample_per_tti = 15360; + openair0_cfg[0].sample_rate = 15.36e6; + openair0_cfg[0].samples_per_frame = nb_sample_per_tti*10; + openair0_cfg[0].rx_bw = 5.0e6; + openair0_cfg[0].tx_bw = 5.0e6; + openair0_cfg[0].num_rb_dl = 50; +#endif + +#if 1 // 20MHz BW + unsigned int nb_sample_per_tti = 30720; + openair0_cfg[0].sample_rate = 30.72e6; + openair0_cfg[0].samples_per_frame = nb_sample_per_tti*10; + openair0_cfg[0].rx_bw = 10.0e6; + openair0_cfg[0].tx_bw = 10.0e6; + openair0_cfg[0].num_rb_dl = 100; +#endif + + const char *openair_dir = getenv("OPENAIR_DIR"); + const char *ini_file = "/targets/ARCH/ADRV9371_ZC706/USERSPACE/PROFILES/ue.band7.tm1.PRB100.adrv9371-zc706_HWgain15dB.ini"; + + int readBlockSize; + void* rxp[nb_antennas_rx]; + void* txp[nb_antennas_tx]; + +// int32_t rxdata[1][nb_sample_per_tti*10+2048]; +#if 0 + int32_t **rxdata; +#endif +// init_thread(100000, 500000, sched_get_priority_max(SCHED_FIFO),"main UE"); + + printf("LTE HARDWARE Latency debug utility \n"); + printf("INIT data buffers \n"); + +#if 0 + rxdata = (int32_t**)memalign(32, nb_antennas_rx*sizeof(int32_t*) ); + rxdata[0] = (int32_t*)memalign(32,(nb_sample_per_tti*10+2048)*sizeof(int32_t)); +#else + rxdata = (int32_t**)malloc16( nb_antennas_rx*sizeof(int32_t*) ); + txdata = (int32_t**)malloc16( nb_antennas_tx*sizeof(int32_t*) ); + rxdata[0] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); + txdata[0] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); +#endif + + printf("INIT done\n"); + + memset(&rf_device, 0, sizeof(openair0_device)); + + rf_device.host_type = BBU_HOST; + openair0_cfg[0].duplex_mode = duplex_mode_FDD; + openair0_cfg[0].rx_num_channels = 1; + openair0_cfg[0].tx_num_channels = 1; + + // configure channel 0 + for (i=0; i<openair0_cfg[0].rx_num_channels; i++) + { + printf("configure channel %d \n",i); + openair0_cfg[0].autocal[i] = 1; + openair0_cfg[0].rx_freq[i] = 2680000000; + openair0_cfg[0].tx_freq[i] = 2560000000; + openair0_cfg[0].rx_gain[i] = 61; + openair0_cfg[0].tx_gain[i] = 90; + } + + if (openair_dir) + { + openair0_cfg[0].configFilename = malloc(strlen(openair_dir) + strlen(ini_file) + 2); + sprintf(openair0_cfg[0].configFilename, "%s/%s", openair_dir, ini_file); + } +// printf("openair0_cfg[0].configFilename:%s\n", openair0_cfg[0].configFilename); + + ret = openair0_device_load( &rf_device, &openair0_cfg[0] ); + if (ret != 0){ + exit_fun("Error loading device library"); + exit(-1); + } + +/* Runtime test + * 30 720 000 samples (4 bytes) for 1 sec (30 720 for 1 ms) + */ + puts( "* Starting the device" ); + +// TIMING +// struct timespec start, stop; // tx_start, tx_stop; +// timing_stats_t rx_stats, tx_stats; + +// rx_stats.name = strdup( "RX" ); +// tx_stats.name = strdup( "TX" ); +// TIMING + + nsamp = 307200; // 1 ms + sendbuff = memalign( 128, nb_antennas_rx * sizeof( uint32_t * ) ); + sendbuff[0] = memalign( 128, nsamp * sizeof( uint32_t ) ); + recvbuff = memalign( 128, nb_antennas_rx * sizeof( uint32_t * ) ); + recvbuff[0] = memalign( 128, nsamp * sizeof( uint32_t ) ); + +// Create dummy buffer + for ( c = 0; c < nsamp; c++ ) { +// sendbuff[0][c] = (c+1); + sendbuff[0][c] = (c+1)*16; +// sendbuff[0][c] = (nsamp-c); + recvbuff[0][c] = 0; + } + + GET_TIME_INIT(3); + + if ( rf_device.trx_start_func( &rf_device ) < 0 ) { + printf( " device could not be started !\n" ); + return -1; + } + + // read 30720 + + // write 30720 ts+2*30720 + + // if tsread >= 2-307200 -> check expected value + status (RxoVer TxUnder) + + rxp[0] = (void*)&rxdata[0][0]; + txp[0] = (void*)&txdata[0][0]; + timestamp = 0; + nsamp = 30720; // 30720 => 1ms buffer + trx_read_cnt = 100000; // 1 loop => 1ms (10sec=10000; 15min = 900000) + antenna_id = 1; + int diff = 0; + int compare_start = 0; + + uint32_t looploop=0; + uint64_t error_cnt = 0; + uint64_t error_ts_start; + + for (i = 0; i < trx_read_cnt; i++) + { + +// printf("\n\n"); + + +// ret = rf_device.trx_read_func( &rf_device, ×tamp, &(rxp[0][(i*30720)%307200]), nsamp, antenna_id ); +// ret = rf_device.trx_read_func( &rf_device, ×tamp, recvbuff[0][(i*30720)%307200], nsamp, antenna_id ); + rxp[0] = (void*)&rxdata[0][(i*30720)%307200]; + GET_TIME_VAL(0); + ret = rf_device.trx_read_func( &rf_device, ×tamp, rxp, nsamp, antenna_id ); + GET_TIME_VAL(1); + + if (ret != nsamp) + { + printf("Error: nsamp received (%d) != nsamp required (%d)\n", ret, nsamp); + fflush(stdout); + return (-1); + } + if (!is_first_ts) + { + first_ts = timestamp; + is_first_ts = 1; + } + +// printf("%d - trx_read_func ret=%d - ts = %d - @=0x%08lx\n", i, ret, timestamp, rxp[0] ); + + txp[0] = (void*)&(txdata[0][ ((i*30720)%307200+2*30720)%307200 ]); +// printf(" i=%d @txp[0][0] = 0x%016lx\n", i, &(((uint32_t *)txp[0])[0]) ); +// printf(" i=%d @txp[0][1] = 0x%016lx\n", i, &(((uint32_t *)txp[0])[1]) ); + + for ( c = 0; c < nsamp; c++ ) + { + (((uint32_t *)txp[0])[c]) = ( (((timestamp+c+2*30720)<<4)&0x0000FFF0) + (((timestamp+c+2*30720)<<8)&0xFFF00000) ); + } + +// printf(" txp[0][%d] = 0x%x\n",0,((uint32_t *)(txp[0]))[0]); +// printf(" txp[0][%d] = 0x%x\n",1,((uint32_t *)(txp[0]))[1]); +// printf(" ...\n"); +// printf(" txp[0][%d] = 0x%x\n",nsamp-2,((uint32_t *)(txp[0]))[nsamp-2]); +// printf(" txp[0][%d] = 0x%x\n",nsamp-1,((uint32_t *)(txp[0]))[nsamp-1]); + + + ret = rf_device.trx_write_func( &rf_device, (timestamp+2*30720), txp, nsamp, antenna_id, false ); + if (ret != nsamp) + { + printf("Error: nsamp sent (%d) != nsamp required (%d)\n", ret, nsamp); + fflush(stdout); + return (-1); + } + +// printf("%d - trx_write_func ret=%d - ts = %d - @=0x%08lx\n", i, ret, (timestamp+2*30720), txp[0] ); + + + if (timestamp >= (first_ts + 2 * 307200)) + { + + // check Rx Overflow + + // check Tx Underflow + + // check Expected Value + for ( c = 0; c < nsamp; c++ ) + { + +// LOOPBACK +#if 1 + expected_value = ((timestamp + c)&0xFFFFFF); + received_value = ((uint32_t *)(rxp[0]))[c]; + received_value = ((received_value)&0xFFF) + ((received_value>>4)&0xFFF000); + + if (compare_start == 0) + { + compare_start = 1; + diff = expected_value - received_value; + } + received_value = (received_value + diff)&0xFFFFFF; + +#if 1 + + if (expected_value != received_value) + { + if(!error_cnt) + error_ts_start = (timestamp + c); + else + { + if (looploop < 32) + printf("%d - %d != %d - ts %d - raw 0x%x - diff %d\n", + looploop, + expected_value, received_value, + (timestamp + c), ((uint32_t *)(rxp[0]))[c], + diff); + looploop++; + } + + error_cnt++; + + if(!(error_cnt%102400)) + printf(" -> error detected : cnt=%d - start=%ld - stop=... diff=%d\n", + error_cnt, + error_ts_start, + diff); + + } + else + { + if(error_cnt) + { + printf(" -> error detected : cnt=%d - start=%ld - stop=%ld\n\n", + error_cnt, + error_ts_start, + (timestamp + c) ); + looploop=0; + } + error_cnt=0; + } +#endif +#endif + +// DEBUG mode 0 +#if 0 + received_value = ((uint32_t *)(rxp[0]))[c]; + received_value = ((received_value)&0xFFF) + ((received_value>>4)&0xFFF000); + received_value = (received_value&0xFFFFFF); + if (compare_start == 0) + { + compare_start = 1; + expected_value = received_value; + } + else + { + expected_value++; + expected_value = (expected_value&0xFFFFFF); + } + + if (expected_value != received_value) + { + if(!error_cnt) + error_ts_start = (timestamp + c); + error_cnt++; + } + else + { + if(error_cnt) + { + printf(" -> error detected : cnt=%d - start=%ld - stop=%ld\n\n", + error_cnt, + error_ts_start, + (timestamp + c) ); + } + error_cnt=0; + } + + + +// if (expected_value != received_value) +// { +// printf("%d -> %d != %d (ts+c=%ld)(raw=0x%08x)\n", +// looploop, +// expected_value, received_value, +// (timestamp + c), +// ((uint32_t *)(rxp[0]))[c] ); +// +// if (received_value) +// expected_value = received_value; +// } +#endif + + } + } + } + + printf("HwLat Application returns !!!\n"); + fflush(stdout); + sleep(1); + + + printf("\n"); + rf_device.trx_end_func( &rf_device ); + + sleep(1); + free(sendbuff[0]); + free(sendbuff); + free(recvbuff[0]); + free(recvbuff); + + exit(0); + + + + return(0); + + + +// puts( "* Frequency modification test" ); +// rf_device.trx_set_freq_func( &rf_device, &openair0_cfg[0], 0 ); + +// puts( "* Gain modification test" ); +// rf_device.trx_set_gains_func( &rf_device, &openair0_cfg[0] ); // NOT working (cf. initialization) + +//#if LTE_UE +// sleep(1); + GET_TIME_VAL(0); + for (i = 0; i < trx_read_cnt; i++) + { + printf("\n"); + ret = rf_device.trx_read_func( &rf_device, ×tamp, rxp, nsamp, antenna_id ); + printf("* timestamp=%ld\n", timestamp); +#if 1 + for (j = 0; j < nsamp; j++) + { + if ( ((uint32_t *)rxp[0])[j] != ((expected_value + j + timestamp)%307200) ) + { + err_cnt++; + printf("rxp[%06d]=0x%08x (expected 0x%08lx)\n", j, ((uint32_t *)rxp[0])[j], ((expected_value + j + timestamp)%307200) ); + } + if (err_cnt >= 128) + { + printf("Error: more than 128 expected value failed !\n"); + i = (trx_read_cnt - 1); + j = nsamp; + break; + } + } + //expected_value = (expected_value + nsamp)%307200; + expected_value = (expected_value)%307200; +#endif + } + GET_TIME_VAL(1); +//#endif + +/* ********** ********** */ +/* RIFFA_CHANNEL_DATA1 */ +/* ********** ********** */ +#if RIFFA_CHANNEL_DATA1 + +// rf_device.trx_get_stats_func( &rf_device ); + + rf_device.trx_end_func( &rf_device ); + + printf("\n* rf_device.trx_read_func(%d) x %d: %.6lf s\n\n", nsamp, i, ((TIME_VAL_TO_MS(1) - TIME_VAL_TO_MS(0)))/1000.0 ); + +// rf_device.trx_get_stats_func( &rf_device ); + +#if 0 + for (i = 0; i < nsamp; i++) + { +// if ( ((uint32_t *)rxp[0])[i] != i) +// { + err_cnt++; + printf("rxp[%06d]=0x%08x (expected 0x%08x)\n", i, ((uint32_t *)rxp[0])[i], i); +// } +// if (err_cnt > 256) +// { +// i = 307200; +// break; +// } + } +#endif +// for (i = 1024-32; i < 1024+32; i++) +// { +//// if ( ((uint32_t *)rxp[0])[i] != i) +//// { +// err_cnt++; +// printf("rxp[%06d]=0x%08x (expected 0x%08x)\n", i, ((uint32_t *)rxp[0])[i], i); +//// } +// if (err_cnt > 256) +// { +// i = 307200; +// break; +// } +// } + printf("RIFFA CHANNEL DATA1 done !!!\n"); + sleep(1); + return(0); +#endif +/* ********** ********** */ +/* RIFFA_CHANNEL_DATA1 */ +/* ********** ********** */ + + + + timestamp = 0; + ret = rf_device.trx_write_func( &rf_device, timestamp, (void**)sendbuff, nsamp, antenna_id, false ); + printf("* rf_device.trx_write_func returns %d\n", ret); + + sleep(1); + + nsamp = 30720; + numIter = 100000; + for ( c = 0; c < numIter; c++ ) + { + fpga_loop ++; + if ( !(fpga_loop % 1000) ) + { + printf("\rtest loop %d / %d", fpga_loop, numIter); + fflush(stdout); + } + +// printf("* TEST : %08d\n", (c+1)); +// measure_time( &rf_device, &start, &stop, &tx_stats, true, 10 ); +// ret = rf_device.trx_write_func( &rf_device, timestamp, (void**)sendbuff, nsamp, antenna_id, false ); +// printf("* rf_device.trx_write_func returns %d\n", ret); +// measure_time( &rf_device, &start, &stop, &tx_stats, false, 10 ); + +// sleep(1); + +// measure_time( &rf_device, &start, &stop, &tx_stats, true, 10 ); + ret = rf_device.trx_read_func( &rf_device, ×tamp, (void**)recvbuff, nsamp, antenna_id ); +// measure_time( &rf_device, &start, &stop, &tx_stats, false, 10 ); + + // Check the data + if (ret > 0) + { +/* ********** ********** */ +/* RIFFA_CHANNEL_TESTER */ +/* ********** ********** */ +#if RIFFA_CHANNEL_TESTER + failure = 0; + for (i = 0; i < ret; i++) + { + if ( ((i%1024) == 0) || ((i%1024) == 1) || ((i%1024) == 2) || ((i%1024) == 3) ) + { + if ( (recvbuff[0])[i] != (1020 + ((i%1024)+1)) ) + { + printf("* ERROR (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) ); + failure = 1; + } + } + else if ( (recvbuff[0])[i] != ((i%1024)+1) ) + { + printf("* ERROR (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) ); + failure = 1; + } + else + { + printf("* DONE (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) ); + } + if(failure) + break; + } + if (failure) + printf("* ERROR recv %08d checked FAILURE ret=%d\n", (c+1), ret); + else + { +// printf("* DONE recv %08d checked SUCCESSFULLY ret=%d\n", (c+1), ret); + } +#endif +/* ********** ********** */ +/* RIFFA_CHANNEL_TESTER2*/ +/* ********** ********** */ +#if RIFFA_CHANNEL_TESTER2 +// printf("* ret=%d timestamp=%ld (%ld)\n", ret, timestamp, (timestamp%307200)); + failure = 0; + for (i = 0; i < ret; i++) + { +// printf("* (recvbuff[0])[%d]: %d\n", i, (uint32_t)(recvbuff[0])[i]); +// printf("* timestamp+(i/1024+1)*1024 - 3 + i%1024: %d\n", (timestamp-nsamp+(i/1024+1)*1024 - 3 + i%1024)%307200 ); + expected_value = ((((i%1024)+1)/*>>4*/)&0x00000FFF); + if ( ((i%1024) == 0) || ((i%1024) == 1) || ((i%1024) == 2) || ((i%1024) == 3) ) + { + expected_value = ((((timestamp-nsamp+(i/1024+1)*1024 - 3 + i%1024))%307200)); + if ( (recvbuff[0])[i] != expected_value) + { + if ( (expected_value == 0) && ((recvbuff[0])[i] != 4915200) ) + { + printf("* ERROR (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], expected_value ); + failure = 1; + } + if ( (expected_value == 0) && ((recvbuff[0])[i] == 4915200) ) + { +// printf("* DONE loop in circular buffer\n"); + } + } + } + else if ( (recvbuff[0])[i] != expected_value ) + { + printf("* ERROR (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) ); + failure = 1; + } + else + { +// printf("* DONE (buff[0])[%d]: %d, expected %d\n", i, (uint32_t)(recvbuff[0])[i], ((i%1024)+1) ); + } +// if(failure) +// break; + } + if (failure) + printf("* ERROR recv %08d checked FAILURE ret=%d\n", (c+1), ret); + else + { +// printf("* DONE recv %08d checked SUCCESSFULLY ret=%d\n", (c+1), ret); + } +#endif +#if LOOPBACK + +#endif + } + else + { + printf("* ERROR rf_device.trx_read_func returns %d\n", ret); + } + + } + printf("\n"); + rf_device.trx_end_func( &rf_device ); + + sleep(1); + free(sendbuff[0]); + free(sendbuff); + free(recvbuff[0]); + free(recvbuff); + + exit(0); + +// END IS HERE ! + + rf_device.trx_set_freq_func(&rf_device,&openair0_cfg[0],0); + + if (rf_device.trx_start_func(&rf_device) != 0 ) { + printf("Could not start the device\n"); + oai_exit=1; + } + + while(!oai_exit){ + + rxp[0] = (void*)&rxdata[0][sub_frame*nb_sample_per_tti]; + + readBlockSize = rf_device.trx_read_func( &rf_device, + ×tamp, + rxp, + nb_sample_per_tti, + 0); + + if ( readBlockSize != nb_sample_per_tti ) + oai_exit = 1; + + sub_frame++; + sub_frame%=10; + + if( sub_frame == 0) + frame_rx++; + + saif_meas(frame_rx, sub_frame); + } + + return(0); +} diff --git a/targets/RT/USER/lte-hwlat2.c b/targets/RT/USER/lte-hwlat2.c new file mode 100644 index 0000000000..67761be9a7 --- /dev/null +++ b/targets/RT/USER/lte-hwlat2.c @@ -0,0 +1,1282 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + + +/* ************************************************************************************************* + + USER GUIDE + + 1 - CONFIGURE TEST SESSION + see TESTS PARAMETERS section below + + 2 - COMPILATION CMD LINE (same as openair compilation) + - NO AVX SUPPORT + /usr/bin/cc -msse4.1 -mssse3 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP -g -DMALLOC_CHECK_=3 -O2 -o lte-hwlat-test lte-hwlat2.c -lrt -lpthread -lm -ldl + - AVX2 Support + /usr/bin/cc -mavx2 -msse4.1 -mssse3 -std=gnu99 -Wall -Wstrict-prototypes -fno-strict-aliasing -rdynamic -funroll-loops -Wno-packed-bitfield-compat -fPIC -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP -g -DMALLOC_CHECK_=3 -O2 -o lte-hwlat-test lte-hwlat2.c -lrt -lpthread -lm -ldl + + + 3 - RUN + sudo cset shield --force --kthread on -c 1-3 // for 4 cores + sudo cset shield --force --kthread on -c 1-7 // for 8 cores + sudo cset shield ./lte-hwlat-test + + 4 - remove cset shield + sudo cset shield --reset + + ***************************************************************************************************/ + +/* ************************************************************************************************* + * TESTS PARAMETERS + */ +#define HWLAT_LOOP_CNT 1000000 /* measurment loop count for each thread*/ +#define HWLAT_TTI_SLEEP_US 250 /* usleep duration -> IQ capture simulation (in µ seconds) */ + +#define RX_NB_TH 6 + +#define CALIB_RT_INTRUMENTATION 0 + +/* Laurent Thpmas instrumentation -> see openair2/UTIL/LOG/log.h for full implementation + -> This is a copy and paste implementation in this file for a self contained source */ +#define INSTRUMENTATION_LT_RDTSC 1 +/* SYRTEM rdtsc instrumentation implementation (see below for more infaormation) */ +#define INSTRUMENTATION_SYR_RDTSC 2 +/* SYRTEM instrumentation using clock_gettime MONOTONIC */ +#define INSTRUMENTATION_SYR_CLOCK_MONO 3 +/* SYRTEM instrumentation using clock_gettime REALTIME */ +#define INSTRUMENTATION_SYR_CLOCK_REALTIME 4 + +#define HWLAT_INSTRUMENTATION INSTRUMENTATION_LT_RDTSC + + +/* Statistics histogram output */ +#define HISTOGRAM_MIN_VALUE 0 +#define HISTOGRAM_MAX_VALUE 2000 +#define HISTOGRAM_STEP 1 +#define HISTOGRAM_SIZE ( ( ( HISTOGRAM_MAX_VALUE - HISTOGRAM_MIN_VALUE ) / HISTOGRAM_STEP ) + 1 ) + + + +/* *************************************************************************************************/ + + +/* + * INCLUDES + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <stdint.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pthread.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <syscall.h> +#include <math.h> +#include <sched.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <sys/sysinfo.h> +#include <unistd.h> +#include <sys/syscall.h> /* For SYS_xxx definitions */ +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif +#include <inttypes.h> + + +/* From rt_wrapper.h +****************************************************************************************/ +#define gettid() syscall(__NR_gettid) // for gettid + +/* From common/utils/itti/assertions.h +****************************************************************************************/ +# define display_backtrace() + +#define _Assert_Exit_ \ +{ \ + fprintf(stderr, "\nExiting execution\n"); \ + display_backtrace(); \ + fflush(stdout); \ + fflush(stderr); \ + exit(EXIT_FAILURE); \ +} + +#define _Assert_(cOND, aCTION, fORMAT, aRGS...) \ +do { \ + if (!(cOND)) { \ + fprintf(stderr, "\nAssertion ("#cOND") failed!\n" \ + "In %s() %s:%d\n" fORMAT, \ + __FUNCTION__, __FILE__, __LINE__, ##aRGS); \ + aCTION; \ + } \ +} while(0) + +#define AssertFatal(cOND, fORMAT, aRGS...) _Assert_(cOND, _Assert_Exit_, fORMAT, ##aRGS) + + +/* From "openair1/PHY/TOOLS/time_meas.h" +****************************************************************************************/ +double cpu_freq_GHz; + + +typedef struct { + + long long in; + long long diff; + long long diff_now; + long long p_time; /*!< \brief absolute process duration */ + long long diff_square; /*!< \brief process duration square */ + long long max; + int trials; + int meas_flag; +} time_stats_t; + +static inline unsigned long long rdtsc_oai(void) __attribute__((always_inline)); +static inline unsigned long long rdtsc_oai(void) +{ + unsigned long long a, d; + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); + return (d<<32) | a; +} + +double get_cpu_freq_GHz(void); + +static inline void reset_meas(time_stats_t *ts) { + + ts->trials=0; + ts->diff=0; + ts->diff_now=0; + ts->p_time=0; + ts->diff_square=0; + ts->max=0; + ts->meas_flag=0; + +} + +double estimate_MHz_syr(void); +static __inline__ uint64_t pickCyclesStart(void); +static __inline__ uint64_t pickCyclesStop(void); + + +/* From "openair2/UTIL/LOG/log.h" +****************************************************************************************/ +extern double cpuf; +extern double cpu_mhz_syr; + + +static __inline__ uint64_t rdtsc(void) { + uint64_t a, d; + __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); + return (d<<32) | a; +} + +typedef struct m { + uint64_t iterations; + uint64_t sum; + uint64_t maxArray[11]; +} Meas; + +static inline void printMeas(char * txt, Meas *M, int period) { + if (M->iterations%period == 0 ) { + char txt2[512]; + sprintf(txt2,"%s avg=%" PRIu64 " iterations=%" PRIu64 " max=%" + PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 "\n", + txt, + M->sum/M->iterations, + M->iterations, + M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4], M->maxArray[5], + M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]); +// SYRTEM : just use printf do not include all LOG_X for this test +//#if DISABLE_LOG_X + printf("%s",txt2); +//#else +// LOG_W(PHY, "%s",txt2); +//#endif + } +} + +static inline int cmpint(const void* a, const void* b) { + uint64_t* aa=(uint64_t*)a; + uint64_t* bb=(uint64_t*)b; + return (int)(*aa-*bb); +} + +static inline uint64_t updateTimes(uint64_t start, Meas *M, int period, char * txt) { + if (start!=0) { + uint64_t end=rdtsc(); + long long diff=(end-start)/(cpuf*1000); + M->maxArray[0]=diff; + M->sum+=diff; + M->iterations++; + qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); +// printMeas(txt,M,period); // SYRTEM : Printed only a the end of the measurment loop + return diff; + } + return 0; +} + +static inline uint64_t updateTimes_syr(uint64_t start, Meas *M, int period, char * txt) { + if (start!=0) { +// uint64_t end=rdtsc(); + uint64_t end=pickCyclesStop(); + long long diff=(long long)((double)(end-start)/(cpu_mhz_syr)); +// long long diff=(end-start)/(cpuf*1000); + M->maxArray[0]=diff; + M->sum+=diff; + M->iterations++; + qsort(M->maxArray, 11, sizeof(uint64_t), cmpint); +// printMeas(txt,M,period); // SYRTEM : Printed only a the end of the measurment loop + return diff; + } + return 0; +} + + + + +#define initRefTimes(a) static __thread Meas a= {0} +#define pickTime(a) uint64_t a=rdtsc() +#define pickTime_syr(a) uint64_t a=pickCyclesStart() +#define readTime(a) a + + + + + + +/* + * DEFINES + */ + +#define TIMESPEC_TO_DOUBLE_US( t ) ( ( (double)t.tv_sec * 1000000 ) + ( (double)t.tv_nsec / 1000 ) ) + +typedef struct histo_time { + double max; + unsigned int count; +} histo_time_t; + +static void measure_time ( struct timespec *start, struct timespec *stop, uint8_t START, uint16_t PRINT_INTERVAL ); +static struct timespec get_timespec_diff( struct timespec *start, struct timespec *stop ); +void histogram_save_in_csv( histo_time_t *histo , char *file_prefix); +histo_time_t *histogram_init( histo_time_t *histo ); +void histogram_store_value( histo_time_t *histo, double value ); + + +#define FIFO_PRIORITY 40 + + + +#define true 1 +#define false 0 + + + + +/* + * STRUCTURES + */ + + +/* stub of UE_rxtx_proc full structure in openair1/PHY/defs.h +*/ +typedef struct UE_rxtx_proc { + int instance_cnt_rxtx; + pthread_t pthread_rxtx; + pthread_cond_t cond_rxtx; + pthread_mutex_t mutex_rxtx; + + + int sub_frame_start; + int sub_frame_step; + unsigned long long gotIQs; + + + unsigned long syr_rdtsc_rxtx_th_unlock_iteration; + uint64_t syr_rdtsc_ue_th_got_iq; + double syr_rdtsc_rxtx_th_unlock; + double syr_rdtsc_rxtx_th_unlock_max; + double syr_rdtsc_rxtx_th_unlock_mean; + double syr_rdtsc_rxtx_th_unlock_min; + histo_time_t *syr_rdtsc_rxtx_th_unlock_histogram; + +} UE_rxtx_proc_t; + + + +/* this structure is used to pass both UE phy vars and + * proc to the function UE_thread_rxn_txnp4 + */ +struct rx_tx_thread_data { + /* PHY_VARS_UE *UE; */ // UE phy vars not used for this test + UE_rxtx_proc_t *proc; // We use a stub of rxtx_proc see definition above +}; + + +// ODD / EVEN Scheduling +#if 0 +typedef struct threads_s { + int iq; + int odd; + int even; +} threads_t; +threads_t threads = { -1, -1, -1 }; // Core number for each thread (iq=3, even=2, odd=1) +#endif + +// SLOT 0 / SLOT 1 parallelization +typedef struct threads_s { + int iq; + int one; + int two; + int three; + int four; + int five; + int six; + int slot1_proc_one; + int slot1_proc_two; + int slot1_proc_three; +} threads_t; +threads_t threads= {7,6,5,4,3,2,1,-1,-1,-1}; + +/* + * FUNCTIONS DEFINITION + */ + +void *UE_thread(void *arg); +void init_UE(int nb_inst); + + + +/* + * GLOBALS VARIABLES + */ + +volatile int oai_exit = 0; +int th_count = 0; +double cpuf; +double cpu_mhz_syr; + + + + + + + +pthread_t pthread_ue; +pthread_attr_t attr_ue; + +UE_rxtx_proc_t **rxtx_proc; + +struct timespec even_start, even_stop; +struct timespec odd_start, odd_stop; + +histo_time_t *th_wake_histogram; + + +/* + * FUNCTIONS + */ + + + +void exit_fun(const char* s) { + if ( s != NULL ) { + printf("%s %s() Exiting OAI softmodem: %s\n",__FILE__, __FUNCTION__, s); + } + + oai_exit = 1; +} + + + + +void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char * name) { + +#ifdef DEADLINE_SCHEDULER + if (sched_runtime!=0) { + struct sched_attr attr= {0}; + attr.size = sizeof(attr); + attr.sched_policy = SCHED_DEADLINE; + attr.sched_runtime = sched_runtime; + attr.sched_deadline = sched_deadline; + attr.sched_period = 0; + AssertFatal(sched_setattr(0, &attr, 0) == 0, + "[SCHED] %s thread: sched_setattr failed %s \n", name, strerror(errno)); + LOG_I(HW,"[SCHED][eNB] %s deadline thread %lu started on CPU %d\n", + name, (unsigned long)gettid(), sched_getcpu()); + } + +#else + if (CPU_COUNT(cpuset) > 0) + AssertFatal( 0 == pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), cpuset), ""); + struct sched_param sp; + sp.sched_priority = sched_fifo; + AssertFatal(pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp)==0, + "Can't set thread priority, Are you root?\n"); + /* Check the actual affinity mask assigned to the thread */ + cpu_set_t *cset=CPU_ALLOC(CPU_SETSIZE); + if (0 == pthread_getaffinity_np(pthread_self(), CPU_ALLOC_SIZE(CPU_SETSIZE), cset)) { + char txt[512]={0}; + for (int j = 0; j < CPU_SETSIZE; j++) + if (CPU_ISSET(j, cset)) + sprintf(txt+strlen(txt), " %d ", j); + printf("CPU Affinity of thread %s is %s\n", name, txt); + } + CPU_FREE(cset); +#endif + + // Lock memory from swapping. This is a process wide call (not constraint to this thread). + mlockall(MCL_CURRENT | MCL_FUTURE); + pthread_setname_np( pthread_self(), name ); + +// SYRTEM : Synchronization thread is not simulated -> just ignore this part of code +// // LTS: this sync stuff should be wrong +// printf("waiting for sync (%s)\n",name); +// pthread_mutex_lock(&sync_mutex); +// printf("Locked sync_mutex, waiting (%s)\n",name); +// while (sync_var<0) +// pthread_cond_wait(&sync_cond, &sync_mutex); +// pthread_mutex_unlock(&sync_mutex); + printf("started %s as PID: %ld\n",name, gettid()); +} + +void init_UE(int nb_inst) +{ + int inst; + for (inst=0; inst < nb_inst; inst++) { + // UE->rfdevice.type = NONE_DEV; +// SYRTEM : we use a stub of phy_var_ue +// PHY_VARS_UE *UE = PHY_vars_UE_g[inst][0]; +// AssertFatal(0 == pthread_create(&UE->proc.pthread_ue, &UE->proc.attr_ue, UE_thread, (void*)UE), ""); + AssertFatal( 0 == pthread_create( &pthread_ue, &attr_ue, UE_thread, NULL ), "" ); + } + + printf("UE threads created by %ld\n", gettid()); +} + + +// SYRTEM - UE synchronization thread is not used in this latency test program +//static void *UE_thread_synch(void *arg) { +// ... +//} + + +// SYRTEM - Stub of UE_thread_rxn_txnp4 +// -> No DSP scheduled +// -> Only thread initialization and thread wake up are kept + +static void *UE_thread_rxn_txnp4(void *arg){ + static __thread int UE_thread_rxtx_retval; + struct rx_tx_thread_data *rtd = arg; + UE_rxtx_proc_t *proc = rtd->proc; + + proc->instance_cnt_rxtx=-1; + + char threadname[256]; + sprintf(threadname,"UE_%d_proc_%d", 0, proc->sub_frame_start); + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + + if ( (proc->sub_frame_start)%RX_NB_TH == 0 && threads.one != -1 ) + CPU_SET(threads.one, &cpuset); + if ( (proc->sub_frame_start)%RX_NB_TH == 1 && threads.two != -1 ) + CPU_SET(threads.two, &cpuset); + if ( (proc->sub_frame_start)%RX_NB_TH == 2 && threads.three != -1 ) + CPU_SET(threads.three, &cpuset); + if ( (proc->sub_frame_start)%RX_NB_TH == 3 && threads.four != -1 ) + CPU_SET(threads.four, &cpuset); + if ( (proc->sub_frame_start)%RX_NB_TH == 4 && threads.five != -1 ) + CPU_SET(threads.five, &cpuset); + if ( (proc->sub_frame_start)%RX_NB_TH == 5 && threads.six != -1 ) + CPU_SET(threads.six, &cpuset); + //CPU_SET(threads.three, &cpuset); + init_thread(900000,1000000 , FIFO_PRIORITY-1, &cpuset, + threadname); + + + proc->syr_rdtsc_rxtx_th_unlock_iteration=0; + proc->syr_rdtsc_rxtx_th_unlock_max=0; + proc->syr_rdtsc_rxtx_th_unlock_mean=0; + proc->syr_rdtsc_rxtx_th_unlock_min=1000; + proc->syr_rdtsc_rxtx_th_unlock_histogram = NULL; + proc->syr_rdtsc_rxtx_th_unlock_histogram = histogram_init (proc->syr_rdtsc_rxtx_th_unlock_histogram); + + while (!oai_exit) { + if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { + printf("[SCHED][UE] error locking mutex for UE RXTX\n" ); + exit_fun("nothing to add"); + } + while (proc->instance_cnt_rxtx < 0) { + // most of the time, the thread is waiting here + pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx ); + } + if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { + printf("[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" ); + exit_fun("nothing to add"); + } + + + proc->syr_rdtsc_rxtx_th_unlock = (double)(pickCyclesStop()-proc->syr_rdtsc_ue_th_got_iq )/cpu_mhz_syr; + + proc->syr_rdtsc_rxtx_th_unlock_iteration++; + + proc->syr_rdtsc_rxtx_th_unlock_mean += proc->syr_rdtsc_rxtx_th_unlock; + if ( proc->syr_rdtsc_rxtx_th_unlock_max < proc->syr_rdtsc_rxtx_th_unlock ) + proc->syr_rdtsc_rxtx_th_unlock_max = proc->syr_rdtsc_rxtx_th_unlock; + if ( proc->syr_rdtsc_rxtx_th_unlock_min > proc->syr_rdtsc_rxtx_th_unlock ) + proc->syr_rdtsc_rxtx_th_unlock_min = proc->syr_rdtsc_rxtx_th_unlock; + histogram_store_value( proc->syr_rdtsc_rxtx_th_unlock_histogram, proc->syr_rdtsc_rxtx_th_unlock ); + + + if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { + printf("[SCHED][UE] error locking mutex for UE RXTX\n" ); + exit_fun("noting to add"); + } + proc->instance_cnt_rxtx--; + if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { + printf("[SCHED][UE] error unlocking mutex for UE RXTX\n" ); + exit_fun("noting to add"); + } + } + +// thread finished + free(arg); + return &UE_thread_rxtx_retval; +} + + + + +void *UE_thread(void *arg) { + + int i = 0; + int hw_loop_cnt = 0; + + int nb_threads = RX_NB_TH; + char threadname[128]; + cpu_set_t cpuset; + struct rx_tx_thread_data *rtd; + UE_rxtx_proc_t *proc; + + CPU_ZERO( &cpuset ); + + if ( threads.iq != -1 ) + CPU_SET( threads.iq, &cpuset ); + init_thread( 100000, 500000, FIFO_PRIORITY, &cpuset, "HDW Threads" ); + + sprintf( threadname, "Main UE %d", 0 ); + pthread_setname_np( pthread_self(), threadname ); + + +// init_UE_threads(UE) + pthread_attr_init( &attr_ue ); + pthread_attr_setstacksize( &attr_ue, 8192 );//5*PTHREAD_STACK_MIN); + + for ( i = 0; i < nb_threads; i++ ) { + + printf("\n"); + + rtd = calloc( 1, sizeof( struct rx_tx_thread_data ) ); + if ( rtd == NULL ) + abort(); + + rtd->proc = rxtx_proc[i]; // &UE->proc.proc_rxtx[i]; + + pthread_mutex_init( &rxtx_proc[i]->mutex_rxtx ,NULL ); // pthread_mutex_init( &UE->proc.proc_rxtx[i].mutex_rxtx,NULL ); + pthread_cond_init( &rxtx_proc[i]->cond_rxtx, NULL ); // pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL); + rtd->proc->sub_frame_start=i; + rtd->proc->sub_frame_step=nb_threads; + printf("Init_UE_threads rtd %d proc %d nb_threads %d i %d\n",rtd->proc->sub_frame_start, rxtx_proc[i]->sub_frame_start,nb_threads, i); + pthread_create( &rxtx_proc[i]->pthread_rxtx, NULL, UE_thread_rxn_txnp4, rtd ); // pthread_create( &UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_thread_rxn_txnp4, rtd); + + usleep(1000); + + } +// init_UE_threads(UE) + + + + int sub_frame=-1; + while ( !oai_exit ) { + + sub_frame++; + sub_frame %= 10; + + proc = rxtx_proc[hw_loop_cnt%RX_NB_TH]; + + // Simulate IQ reception + usleep( HWLAT_TTI_SLEEP_US ); + + proc->syr_rdtsc_ue_th_got_iq = pickCyclesStart(); + + AssertFatal(pthread_mutex_lock(&proc->mutex_rxtx) ==0,""); + + proc->instance_cnt_rxtx++; + if ( proc->instance_cnt_rxtx == 0 ) { + if ( pthread_cond_signal( &proc->cond_rxtx) != 0 ) { + exit_fun( "nothing to add" ); + } + } else { + if ( proc->instance_cnt_rxtx > 2 ) + exit_fun( "instance_cnt_rxtx > 2" ); + } + + AssertFatal( pthread_cond_signal( &proc->cond_rxtx ) == 0 ,"" ); + AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,""); + + + /* Do not go indefinitely */ + hw_loop_cnt++; + + if ( hw_loop_cnt%1000 == 0 ) + { + printf("\r%d/%d",hw_loop_cnt,HWLAT_LOOP_CNT*RX_NB_TH); + fflush(stdout); + } + + if (hw_loop_cnt >= HWLAT_LOOP_CNT*RX_NB_TH) + { + printf("\n\n"); + for (i=0 ; i<RX_NB_TH ; i++) + { + proc = rxtx_proc[i]; + pthread_getname_np(proc->pthread_rxtx,threadname,128 ); + printf("RxTX Thread unlock latency on thread %s (it. %ld) (us) : max=%8.3f - mean=%8.3f - min=%8.3f\n", + threadname, + proc->syr_rdtsc_rxtx_th_unlock_iteration, + proc->syr_rdtsc_rxtx_th_unlock_max, + proc->syr_rdtsc_rxtx_th_unlock_mean/proc->syr_rdtsc_rxtx_th_unlock_iteration, + proc->syr_rdtsc_rxtx_th_unlock_min); + + histogram_save_in_csv(proc->syr_rdtsc_rxtx_th_unlock_histogram, threadname ); + + } + printf("\n\n"); + oai_exit = 1; + } + + } // while !oai_exit + + oai_exit = 1; + + return NULL; +} + +#define CALIB_LOOP_CNT 1000000 //2000000000 +#define CALIB_LOOP_REPORT_PERIOD 1000 +#define CALIB_LOOP_UP_THRESHOLD 20 // 20 -> for NG Intel flat model +#define CALIB_USLEEP 250 + +int main( void ) +{ + + int i; + + +#if CALIB_RT_INTRUMENTATION + uint32_t calib_loop_count; + + + uint64_t lt_overhead_cur; + uint64_t lt_overhead_min; + uint64_t lt_overhead_max; + uint64_t lt_overhead_mean; + histo_time_t *lt_overhead_histogram = NULL; + + uint64_t lt_syr_overhead_cur; + uint64_t lt_syr_overhead_min; + uint64_t lt_syr_overhead_max; + uint64_t lt_syr_overhead_mean; + histo_time_t *lt_syr_overhead_histogram = NULL; + + double syr_rdtsc_overhead_cur; + double syr_rdtsc_overhead_min; + double syr_rdtsc_overhead_max; + double syr_rdtsc_overhead_mean; + histo_time_t *syr_rdtsc_overhead_histogram = NULL; + + double syr_clock_gettime_overhead_cur; + double syr_clock_gettime_overhead_min; + double syr_clock_gettime_overhead_max; + double syr_clock_gettime_overhead_mean; + histo_time_t *syr_clock_gettime_overhead_histogram = NULL; + + + uint64_t cycles_start; + uint64_t cycles_stop; + + uint64_t cycles_diff; + uint64_t cycles_diff_max = 0; + + + struct timespec start; + struct timespec stop; +#endif + + cpuf = get_cpu_freq_GHz(); + cpu_mhz_syr = estimate_MHz_syr(); + + printf("\n\ncpuf %f - cpu_mhz_syr %f\n\n", cpuf, cpu_mhz_syr); + +#if CALIB_RT_INTRUMENTATION + + /* ********************************************************************************************** */ + /* CALIBRATION */ + /* ********************************************************************************************** */ + + /* ************************************************************* + Laurent Thomas instrumentation overhead + */ + printf("\nCalibrating OAI Realtime Instrumentation (Laurent Thomas imp.)\n"); + calib_loop_count = CALIB_LOOP_CNT; + initRefTimes(lt_instru_calib); // Laurent Thomas realtime instrumentation calibration measurments + lt_overhead_min = 1000; + lt_overhead_max = 0; + lt_overhead_mean = 0; + lt_overhead_histogram = histogram_init( lt_overhead_histogram ); + while(calib_loop_count) + { + pickTime(lt_start); + +// asm volatile(""); // Nop instruction + usleep(CALIB_USLEEP); + + lt_overhead_cur = updateTimes( readTime(lt_start), + <_instru_calib, + CALIB_LOOP_CNT, + "Laurent Thomas realtime instrumentation calibration measurments"); + + lt_overhead_mean += lt_overhead_cur; + if ( lt_overhead_max < lt_overhead_cur ) + lt_overhead_max = lt_overhead_cur; + if ( lt_overhead_min > lt_overhead_cur ) + lt_overhead_min = lt_overhead_cur; + histogram_store_value( lt_overhead_histogram, (double)lt_overhead_cur ); + + if ( calib_loop_count%CALIB_LOOP_REPORT_PERIOD == 0 ) + { + printf("\r%d/%d",calib_loop_count,CALIB_LOOP_CNT); + fflush(stdout); + } + + calib_loop_count--; + } + lt_overhead_mean = lt_overhead_mean/CALIB_LOOP_CNT; + +// printMeas("\nLaurent Thomas realtime instrumentation calibration measurments",<_instru_calib,CALIB_LOOP_CNT); + + + /* ************************************************************* + Laurent Thomas instrumentation overhead + */ + printf("\nCalibrating OAI Realtime Instrumentation - SYRTEM revisited\n"); + calib_loop_count = CALIB_LOOP_CNT; + initRefTimes(lt_instru_calib_syr); // Laurent Thomas realtime instrumentation calibration measurments + lt_syr_overhead_min = 1000; + lt_syr_overhead_max = 0; + lt_syr_overhead_mean = 0; + lt_syr_overhead_histogram = histogram_init( lt_syr_overhead_histogram ); + while(calib_loop_count) + { + pickTime_syr(lt_start_syr); + +// asm volatile(""); // Nop instruction + usleep(CALIB_USLEEP); + + lt_syr_overhead_cur = updateTimes_syr(readTime(lt_start_syr), <_instru_calib_syr, CALIB_LOOP_CNT, "Laurent Thomas realtime instrumentation calibration measurments (SYRTEM Update)"); + + lt_syr_overhead_mean += lt_syr_overhead_cur; + if ( lt_syr_overhead_max < lt_syr_overhead_cur ) + lt_syr_overhead_max = lt_syr_overhead_cur; + if ( lt_syr_overhead_min > lt_syr_overhead_cur ) + lt_syr_overhead_min = lt_syr_overhead_cur; + histogram_store_value( lt_syr_overhead_histogram, (double)lt_syr_overhead_cur ); + + if ( calib_loop_count%CALIB_LOOP_REPORT_PERIOD == 0 ) + { + printf("\r%d/%d",calib_loop_count,CALIB_LOOP_CNT); + fflush(stdout); + } + + calib_loop_count--; + } + lt_syr_overhead_mean = lt_syr_overhead_mean / CALIB_LOOP_CNT; + +// printMeas("\nLaurent Thomas realtime instrumentation calibration measurments (SYRTEM Update)",<_instru_calib_syr,CALIB_LOOP_CNT); + + + + /* ************************************************************* + SYRTEM RDTSC instrumentation overhead + */ + printf("\nCalibrating SYRTEM RDTSC Realtime Instrumentation\n"); + calib_loop_count = CALIB_LOOP_CNT; + syr_rdtsc_overhead_min = 1000; + syr_rdtsc_overhead_max = 0; + syr_rdtsc_overhead_mean = 0; + syr_rdtsc_overhead_histogram = histogram_init( syr_rdtsc_overhead_histogram ); + while(calib_loop_count) + { + + cycles_start = pickCyclesStart(); + +// asm volatile(""); // Nop instruction + usleep(CALIB_USLEEP); + + cycles_stop = pickCyclesStop(); + + cycles_diff = cycles_stop - cycles_start; + if(cycles_diff_max < cycles_diff) + cycles_diff_max = cycles_diff; + + syr_rdtsc_overhead_cur = (double)cycles_diff/cpu_mhz_syr; + + syr_rdtsc_overhead_mean += syr_rdtsc_overhead_cur; + if ( syr_rdtsc_overhead_max < syr_rdtsc_overhead_cur ) + syr_rdtsc_overhead_max = syr_rdtsc_overhead_cur; + if ( syr_rdtsc_overhead_min > syr_rdtsc_overhead_cur ) + syr_rdtsc_overhead_min = syr_rdtsc_overhead_cur; + histogram_store_value( syr_rdtsc_overhead_histogram, (double)syr_rdtsc_overhead_cur ); + + if ( calib_loop_count%CALIB_LOOP_REPORT_PERIOD == 0 ) + { + printf("\r%d/%d",calib_loop_count,CALIB_LOOP_CNT); + fflush(stdout); + } + + calib_loop_count--; + } + syr_rdtsc_overhead_mean = syr_rdtsc_overhead_mean / CALIB_LOOP_CNT; + +// printf("\nSYRTEM RDTSV realtime instrumentation calibration : cycles_diff_max %ld - tsc_duration_max %f us\n ", cycles_diff_max, tsc_duration_max); + + + + /* ************************************************************* + SYRTEM Clock_gettime MONOTONIC instrumentation overhead + */ + printf("\nCalibrating SYRTEM clock_gettime Realtime Instrumentation\n"); + calib_loop_count = CALIB_LOOP_CNT; + syr_clock_gettime_overhead_min = 1000; + syr_clock_gettime_overhead_max = 0; + syr_clock_gettime_overhead_mean = 0; + syr_clock_gettime_overhead_histogram = histogram_init( syr_clock_gettime_overhead_histogram ); + while(calib_loop_count) + { + + clock_gettime( CLOCK_MONOTONIC, &start ); + +// asm volatile(""); // Nop instruction + usleep(CALIB_USLEEP); + + clock_gettime( CLOCK_MONOTONIC, &stop ); + syr_clock_gettime_overhead_cur = TIMESPEC_TO_DOUBLE_US( get_timespec_diff( &start, &stop ) ); + + syr_clock_gettime_overhead_mean += syr_clock_gettime_overhead_cur; + if ( syr_clock_gettime_overhead_max < syr_clock_gettime_overhead_cur ) + syr_clock_gettime_overhead_max = syr_clock_gettime_overhead_cur; + if ( syr_clock_gettime_overhead_min > syr_clock_gettime_overhead_cur ) + syr_clock_gettime_overhead_min = syr_clock_gettime_overhead_cur; + histogram_store_value( syr_clock_gettime_overhead_histogram, (double)syr_clock_gettime_overhead_cur ); + + if ( calib_loop_count%CALIB_LOOP_REPORT_PERIOD == 0 ) + { + printf("\r%d/%d",calib_loop_count,CALIB_LOOP_CNT); + fflush(stdout); + } + + calib_loop_count--; + } + syr_clock_gettime_overhead_mean = syr_clock_gettime_overhead_mean / CALIB_LOOP_CNT; + +// printf("\nSYRTEM clock_gettime MONOTONIC calibration : clock_gettime duration_max %f us\n ", max); + + + printf("\n"); + + printf("OAI LT RT profiling overhead (it. %d) (us) : max=%8ld - mean=%8ld - min=%8ld\n", + CALIB_LOOP_CNT, + lt_overhead_max, lt_overhead_mean, lt_overhead_min); + printf("OAI SYR RT profiling overhead (it. %d) (us) : max=%8ld - mean=%8ld - min=%8ld\n", + CALIB_LOOP_CNT, + lt_syr_overhead_max, lt_syr_overhead_mean, lt_syr_overhead_min); + printf("SYR RDTSC profiling overhead (it. %d) (us) : max=%8.3f - mean=%8.3f - min=%8.3f\n", + CALIB_LOOP_CNT, + syr_rdtsc_overhead_max, syr_rdtsc_overhead_mean, syr_rdtsc_overhead_min); + printf("SYR clock_gettime profiling overhead (it. %d) (us): max=%8.3f - mean=%8.3f - min=%8.3f\n", + CALIB_LOOP_CNT, + syr_clock_gettime_overhead_max, syr_clock_gettime_overhead_mean, syr_clock_gettime_overhead_min); + + return 0; +#endif + + rxtx_proc = calloc( RX_NB_TH, sizeof( UE_rxtx_proc_t* ) ); + for (i=0 ; i<RX_NB_TH; i++) + rxtx_proc[i] = calloc( 1, sizeof( UE_rxtx_proc_t ) ); + + + th_wake_histogram = histogram_init( th_wake_histogram ); + + init_UE( 1 ); + + while ( !oai_exit ) + sleep( 1 ); + + return 0; +} + + +double estimate_MHz_syr(void) +{ + //copied blantantly from http://www.cs.helsinki.fi/linux/linux-kernel/2001-37/0256.html + /* + * $Id: MHz.c,v 1.4 2001/05/21 18:58:01 davej Exp $ + * This file is part of x86info. + * (C) 2001 Dave Jones. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Estimate CPU MHz routine by Andrea Arcangeli <andrea@suse.de> + * Small changes by David Sterba <sterd9am@ss1000.ms.mff.cuni.cz> + * + */ + + struct timespec start; + struct timespec stop; + + unsigned long long int cycles[2]; /* must be 64 bit */ + double microseconds; /* total time taken */ + + + /* get this function in cached memory */ + cycles[0] = rdtsc (); + clock_gettime( CLOCK_REALTIME, &start ); + + /* we don't trust that this is any specific length of time */ + usleep (100000); + + cycles[1] = rdtsc (); + clock_gettime( CLOCK_REALTIME, &stop ); + microseconds = TIMESPEC_TO_DOUBLE_US( get_timespec_diff( &start, &stop ) ); + + unsigned long long int elapsed = 0; + if (cycles[1] < cycles[0]) + { + //printf("c0 = %llu c1 = %llu",cycles[0],cycles[1]); + elapsed = UINT32_MAX - cycles[0]; + elapsed = elapsed + cycles[1]; + //printf("c0 = %llu c1 = %llu max = %llu elapsed=%llu\n",cycles[0], cycles[1], UINT32_MAX,elapsed); + } + else + { + elapsed = cycles[1] - cycles[0]; + // printf("\nc0 = %llu c1 = %llu elapsed=%llu\n",cycles[0], cycles[1],elapsed); + } + + double mhz = elapsed / microseconds; + + + //printf("%llg MHz processor (estimate). diff cycles=%llu microseconds=%llu \n", mhz, elapsed, microseconds); + //printf("%g elapsed %llu microseconds %llu\n",mhz, elapsed, microseconds); + return (mhz); +} + + + +/** TSC Timestamp references + + - http://oliveryang.net/2015/09/pitfalls-of-TSC-usage/#312-tsc-sync-behaviors-on-smp-system + - https://www.intel.com/content/www/us/en/embedded/training/ia-32-ia-64-benchmark-code-execution-paper.html + - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3b-part-2-manual.pdf + + - http://blog.tinola.com/?e=54 + - https://stackoverflow.com/questions/24392392/getting-tsc-frequency-from-proc-cpuinfo !! warning on turbo + - https://gist.github.com/nfarring/1624742 + - https://www.lmax.com/blog/staff-blogs/2015/10/25/time-stamp-counters/ + - https://github.com/cyring/CoreFreq + - https://patchwork.kernel.org/patch/9438133/ --> TSC_ADJUST - to be checked + -> https://software.intel.com/en-us/forums/software-tuning-performance-optimization-platform-monitoring/topic/388964 + - https://www.google.fr/url?sa=t&rct=j&q=&esrc=s&source=web&cd=11&ved=0ahUKEwjwpJbem5DVAhWBDpoKHXv0Dt04ChAWCCIwAA&url=https%3A%2F%2Fsigarra.up.pt%2Ffeup%2Fpt%2Fpub_geral.show_file%3Fpi_gdoc_id%3D809041&usg=AFQjCNFHTMjmjWMG6QSVnLDflEoU0RavKw&cad=rja + - https://unix4lyfe.org/benchmarking/ + - https://stackoverflow.com/questions/27693145/rdtscp-versus-rdtsc-cpuid + - https://github.com/dterei/tsc/blob/master/tsc.h + - https://software.intel.com/en-us/forums/intel-isa-extensions/topic/280440 + - https://stackoverflow.com/questions/19941588/wrong-clock-cycle-measurements-with-rdtsc + + + +*/ + + + + + + +static __inline__ uint64_t pickCyclesStart(void) { + unsigned cycles_low, cycles_high; + asm volatile( "CPUID\n\t" // serialize + "RDTSC\n\t" // read clock + "MOV %%edx, %0\n\t" + "MOV %%eax, %1\n\t" + : "=r" (cycles_high), "=r" (cycles_low) + :: "%rax", "%rbx", "%rcx", "%rdx" ); +return ((uint64_t) cycles_high << 32) | cycles_low; +} + +static __inline__ uint64_t pickCyclesStop(void) { + uint32_t eax, edx; + + __asm__ __volatile__("rdtscp" + : "=a" (eax), "=d" (edx) + : + : "%ecx", "memory"); + +return (((uint64_t)edx << 32) | eax); +} + + + + + + + + +/************************************************************************************** + EXTRACT from openair1/PHY/TOOLS/time_meas.c +***************************************************************************************/ +double get_cpu_freq_GHz(void) { + + time_stats_t ts = {0}; + reset_meas(&ts); + ts.trials++; + ts.in = rdtsc_oai(); + sleep(1); + ts.diff = (rdtsc_oai()-ts.in); + cpu_freq_GHz = (double)ts.diff/1000000000; + printf("CPU Freq is %f \n", cpu_freq_GHz); + return cpu_freq_GHz; +} + + + +/************************************************************************************** + SYRTEM STATISTICS HELPER +***************************************************************************************/ + + + +histo_time_t *histogram_init(histo_time_t *histo ) +{ + int i = 0; + double max_val = HISTOGRAM_MIN_VALUE + HISTOGRAM_STEP; + + histo = calloc( HISTOGRAM_SIZE, sizeof( histo_time_t ) ); + if ( histo == NULL ) { + printf( "ERROR allocating histogram structure !\n" ); + return NULL; + } + + for ( i = 0; i < HISTOGRAM_SIZE; i++ ) { + histo[i].max = max_val; + max_val += HISTOGRAM_STEP; + } + + return histo; +} + + +void histogram_store_value( histo_time_t *histo, double value ) +{ + int i = 0; + + for ( i = 0; i < HISTOGRAM_SIZE; i++ ) { + if ( histo[i].max >= value || ( i + 1 ) == HISTOGRAM_SIZE ) { + histo[i].count++; + break; + } + } +} + + +void histogram_save_in_csv( histo_time_t *histo , char *file_sufix) +{ + char *csv_filename; + char month[3], day[3], hour[3], min[3], sec[3]; + time_t curr_time; + struct tm *datetime; + + curr_time = time( NULL ); + datetime = localtime( &curr_time ); + + csv_filename = calloc( sizeof( char ), 64 ); + if ( csv_filename == NULL ) { + return; + } + + memset( csv_filename, 0x00, 64 ); + memset( month, 0x00, 3 ); + memset( day, 0x00, 3 ); + memset( hour, 0x00, 3 ); + memset( min, 0x00, 3 ); + memset( sec, 0x00, 3 ); + +/* Month. */ + if ( datetime->tm_mon < 9 ) + snprintf( month, 3, "0%d", datetime->tm_mon + 1 ); + else + snprintf( month, 3, "%d", datetime->tm_mon + 1 ); + +/* Day. */ + if ( datetime->tm_mday < 10 ) + snprintf( day, 3, "0%d", datetime->tm_mday ); + else + snprintf( day, 3, "%d", datetime->tm_mday ); + +/* Hour. */ + if ( datetime->tm_hour < 10 ) + snprintf( hour, 3, "0%d", datetime->tm_hour ); + else + snprintf( hour, 3, "%d", datetime->tm_hour ); + +/* Minute. */ + if ( datetime->tm_min < 10 ) + snprintf( min, 3, "0%d", datetime->tm_min ); + else + snprintf( min, 3, "%d", datetime->tm_min ); + +/* Second. */ + if ( datetime->tm_sec < 10 ) + snprintf( sec, 3, "0%d", datetime->tm_sec ); + else + snprintf( sec, 3, "%d", datetime->tm_sec ); + + snprintf( csv_filename, 63, "ADRV9371_ZC706_HISTO_UEtoRXTX_%d%s%s%s%s%s_%s.csv", + datetime->tm_year + 1900, month, day, hour, min, sec, file_sufix ); + + FILE *fp; + int i = 0; + int min_val = 0; + + fp = fopen( csv_filename, "w+" ); + + fprintf( fp, "range;count\n" ); + + for ( i = 0; i < HISTOGRAM_SIZE; i++ ) { + if ( i + 1 == HISTOGRAM_SIZE ) + fprintf( fp, "%u+;%u\n", min_val, histo[i].count ); + else + fprintf( fp, "%u-%.0f;%u\n", min_val, histo[i].max, histo[i].count ); + min_val = histo[i].max; + } + + fclose( fp ); +} + + + +static struct timespec get_timespec_diff( + struct timespec *start, + struct timespec *stop ) +{ + struct timespec result; + + if ( ( stop->tv_nsec - start->tv_nsec ) < 0 ) { + result.tv_sec = stop->tv_sec - start->tv_sec - 1; + result.tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; + } + else { + result.tv_sec = stop->tv_sec - start->tv_sec; + result.tv_nsec = stop->tv_nsec - start->tv_nsec; + } + + return result; +} + + +static void measure_time ( + struct timespec *start, + struct timespec *stop, + uint8_t START, + uint16_t PRINT_INTERVAL ) +{ + static double max = 0; + static double min = 0; + static double total = 0; + static int count = 0; + + if ( START ) { + clock_gettime( CLOCK_REALTIME, start ); + } + else { + clock_gettime( CLOCK_REALTIME, stop ); + + struct timespec diff; + double current = 0; + + diff = get_timespec_diff( start, stop ); +// current = ( (double)diff.tv_sec * 1000000 ) + ( (double)diff.tv_nsec / 1000 ); + current = TIMESPEC_TO_DOUBLE_US( diff ); + + if ( current > max ) { + max = current; + } + if ( min == 0 || current < min ) { + min = current; + } + total += current; + + histogram_store_value( th_wake_histogram, current ); + + if ( count % PRINT_INTERVAL == 0 && count != 0 ) { + double avg = total / ( count + 1 ); + printf( "[%d] Current : %.2lf µs, Min : %.2lf µs, Max : %.2lf µs, Moy : %.2lf µs\n", + count, current, min, max, avg ); + } + count++; + } +} + + + + + + + + + + + + + + + + diff --git a/targets/SIMU/USER/oaisim_functions.c b/targets/SIMU/USER/oaisim_functions.c index ceaae1958b..c6907e666b 100644 --- a/targets/SIMU/USER/oaisim_functions.c +++ b/targets/SIMU/USER/oaisim_functions.c @@ -1704,7 +1704,7 @@ void update_otg_eNB(module_id_t enb_module_idP, unsigned int ctime) } #else -#if 0 // defined(EXMIMO) || defined(OAI_USRP) +#if 0 // defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706) if (otg_enabled==1) { ctime = frame * 100; diff --git a/targets/build_oai.bash b/targets/build_oai.bash index cfe5e35d26..05b14a541b 100755 --- a/targets/build_oai.bash +++ b/targets/build_oai.bash @@ -344,6 +344,10 @@ build_enb(){ SOFTMODEM_DIRECTIVES="$SOFTMODEM_DIRECTIVES USRP=1 " fi + if [ $HW = "ADRV9371_ZC706" ]; then + SOFTMODEM_DIRECTIVES="$SOFTMODEM_DIRECTIVES ADRV9371_ZC706=1 " + fi + if [ $HW = "EXMIMO" ]; then SOFTMODEM_DIRECTIVES="$SOFTMODEM_DIRECTIVES EXMIMO=1 " fi -- GitLab