diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 7907d68f45..9a944efa68 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -36,12 +36,16 @@ set (OPENAIR1_DIR ${OPENAIR_DIR}/openair1)
set (OPENAIR2_DIR ${OPENAIR_DIR}/openair2)
set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3)
set (OPENAIR_TARGETS ${OPENAIR_DIR}/targets)
-set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3)
+set (OPENAIR3_DIR ${OPENAIR_DIR}/openair3)
set (OPENAIR_CMAKE ${OPENAIR_DIR}/cmake_targets)
set (OPENAIR_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
project (OpenAirInterface)
+add_subdirectory(${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lms7002m lms7002m)
+add_subdirectory(${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR lmsSDR)
+add_subdirectory(${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/Si5351C Si5351C)
+
###########################################
# macros to define options as there is numerous options in oai
################################################
@@ -159,14 +163,20 @@ set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -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"
)
set(CMAKE_CXX_FLAGS
- "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR}"
+ "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} -std=c++11 "
)
+
+
+#########################
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath -Wl,${OPENAIR_TARGETS}/bin")
+#########################
# set a flag for changes in the source code
# these changes are related to hardcoded path to include .h files
add_definitions(-DCMAKER)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS} -g -DMALLOC_CHECK_=3 -O2")
+Message("RF_BOARD is ${RF_BOARD}")
# Below has been put in comment because does not work with
# SVN authentication.
#
@@ -244,6 +254,9 @@ endif (${RTAI})
set(asn1c_call "${OPENAIR_CMAKE}/tools/generate_asn1")
set(asn1_generated_dir ${OPENAIR_BIN_DIR})
+set(protoc_call "${OPENAIR_CMAKE}/tools/generate_protobuf")
+set(protobuf_generated_dir ${OPENAIR_BIN_DIR})
+
# RRC
######
add_list2_option(RRC_ASN1_VERSION "Rel10" "ASN.1 version of RRC interface" "Rel8" "Rel10" "CBA")
@@ -404,8 +417,55 @@ add_list1_option(NB_ANTENNAS_RX "2" "Number of antennas in reception" "1" "2" "4
add_list1_option(NB_ANTENNAS_TX "2" "Number of antennas in transmission" "1" "2" "4")
add_list1_option(NB_ANTENNAS_TXRX "2" "Number of antennas in ????" "1" "2" "4")
-add_list2_option(RF_BOARD "EXMIMO" "RF head type" "False" "EXMIMO" "OAI_USRP" "ETHERNET" "OAI_BLADERF" "CPRIGW")
+add_list2_option(RF_BOARD "EXMIMO" "RF head type" "None" "EXMIMO" "OAI_USRP" "OAI_BLADERF" "CPRIGW" "OAI_LMSSDR")
+add_list2_option(TRANSP_PRO "None" "Transport protocol type" "None" "ETHERNET")
+
+
+# include RF devices / transport protocols library modules
+######################################################################
+
+include_directories("${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/")
+include_directories ("${OPENAIR_TARGETS}/ARCH/EXMIMO/DEFS/")
+#set (option_HWEXMIMOLIB_lib "-l ")
+set(HWLIB_EXMIMO_SOURCE
+ ${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
+ ${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c
+ )
+add_library(oai_exmimodevif MODULE ${HWLIB_EXMIMO_SOURCE} )
+
+include_directories("${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/")
+set (option_HWUSRPLIB_lib "-l uhd")
+set(HWLIB_USRP_SOURCE
+ ${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
+ )
+add_library(oai_usrpdevif MODULE ${HWLIB_USRP_SOURCE} )
+
+include_directories("${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/")
+set (option_HWBLADERFLIB_lib "-l bladerf")
+set(HWLIB_BLADERF_SOURCE
+ ${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
+ )
+add_library(oai_bladerfdevif MODULE ${HWLIB_BLADERF_SOURCE} )
+
+include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/")
+set (option_HWLMSSDRLIB_lib "-l LMS_SDR -l LMS7002M -l Si5351C")
+set(HWLIB_LMSSDR_SOURCE
+ ${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp
+ )
+add_library(oai_lmssdrdevif MODULE ${HWLIB_LMSSDR_SOURCE} )
+
+include_directories("${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/")
+set(TPLIB_ETHERNET_SOURCE
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
+ )
+add_library(oai_eth_transpro MODULE ${TPLIB_ETHERNET_SOURCE} )
+
+
+# RF devices / transport protocols settings
+######################################################################
if (${RF_BOARD} STREQUAL "EXMIMO")
set(DRIVER2013)
include_directories ("${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/")
@@ -413,6 +473,7 @@ if (${RF_BOARD} STREQUAL "EXMIMO")
set(HW_SOURCE ${HW_SOURCE}
${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
${OPENAIR_TARGETS}/ARCH/EXMIMO/USERSPACE/LIB/gain_control.c)
+ set(option_HW_lib "-rdynamic -ldl")
elseif (${RF_BOARD} STREQUAL "OAI_USRP")
include_directories("${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/")
@@ -420,8 +481,7 @@ elseif (${RF_BOARD} STREQUAL "OAI_USRP")
set(HW_SOURCE ${HW_SOURCE}
${OPENAIR_TARGETS}/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp)
LINK_DIRECTORIES("/opt/lib")
- set(option_HW_lib "uhd")
- #set(LOWLATENCY False)
+ set(option_HW_lib "-luhd -rdynamic -ldl")
elseif (${RF_BOARD} STREQUAL "OAI_BLADERF")
include_directories("${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/")
@@ -431,24 +491,48 @@ elseif (${RF_BOARD} STREQUAL "OAI_BLADERF")
${OPENAIR_TARGETS}/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
)
LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu")
- set(option_HW_lib "bladeRF")
+
+ set(option_HW_lib "bladeRF -rdynamic -ldl")
#set(LOWLATENCY False)
-elseif (${RF_BOARD} STREQUAL "ETHERNET")
- include_directories ("${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB")
- set(HW_SOURCE ${HW_SOURCE}
- ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
- )
- #set(LOWLATENCY True)
-
+elseif (${RF_BOARD} STREQUAL "OAI_LMSSDR")
+ include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB")
+ include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR")
+ include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lms7002m")
+ include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/Si5351C")
+ include_directories("${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lmsSDR/LMS_StreamBoard")
+ LINK_DIRECTORIES("/usr/lib/x86_64-linux-gnu")
+ LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/lmsSDR")
+ LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/lms7002m")
+ LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/Si5351C")
+ set(HW_SOURCE ${HW_SOURCE} ${OPENAIR_TARGETS}/ARCH/LMSSDR/USERSPACE/LIB/lms_lib.cpp)
+ set(LOWLATENCY False)
+ set(option_HW_lib "-lLMS_SDR -lLMS7002M -lSi5351C -rdynamic -ldl")
+
elseif (${RF_BOARD} STREQUAL "CPRIGW")
set(HW_SOURCE ${HW_SOURCE}
${OPENAIR_TARGETS}/ARCH/CPRIGW/USERSPACE/LIB/cprigw_lib.c
)
include_directories("${OPENAIR_TARGETS}/ARCH/CPRIGW/USERSPACE/LIB/")
- set(option_HW_lib "-rdynamic dl")
+ set(option_HW_lib "-rdynamic dl")
+
endif (${RF_BOARD} STREQUAL "EXMIMO")
+
+if (${TRANSP_PRO} STREQUAL "ETHERNET")
+
+ include_directories ("${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB")
+ set(TRANSPORT_SOURCE ${TRANSPORT_SOURCE}
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
+ ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
+ )
+ set(option_TP_lib "-rdynamic -ldl")
+
+
+endif (${TRANSP_PRO} STREQUAL "ETHERNET")
+##########################################################
+
include_directories ("${OPENAIR_TARGETS}/ARCH/COMMON")
Message("LOWLATENCY flag is ${LOWLATENCY}")
@@ -474,6 +558,9 @@ add_list_string_option(PACKAGE_NAME "NotDefined" "As per attribute name")
add_boolean_option(MESSAGE_CHART_GENERATOR False "For generating sequence diagrams")
add_boolean_option(MESSAGE_CHART_GENERATOR_RLC_MAC False "trace RLC-MAC exchanges in sequence diagrams")
add_boolean_option(MESSAGE_CHART_GENERATOR_PHY False "trace some PHY exchanges in sequence diagrams")
+
+add_boolean_option(ENB_AGENT True "enable eNB agent to inteface with a SDN contrller")
+
########################
# Include order
##########################
@@ -1403,10 +1490,11 @@ add_definitions(-DASN1_MINIMUM_VERSION=924)
#################################
# add executables for operation
-#################################""
+#################################
# lte-softmodem is both eNB and UE implementation
###################################################
+
add_executable(lte-softmodem
${rrc_h}
${s1ap_h}
@@ -1424,6 +1512,7 @@ add_executable(lte-softmodem
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
${GTPU_need_ITTI}
${HW_SOURCE}
+ ${TRANSPORT_SOURCE}
${RTAI_SOURCE}
${XFORMS_SOURCE}
${XFORMS_SOURCE_SOFTMODEM}
@@ -1431,13 +1520,14 @@ add_executable(lte-softmodem
target_link_libraries (lte-softmodem
-Wl,--start-group
- RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB}
+ RRC_LIB S1AP_LIB S1AP_ENB GTPV1U SECU_CN SECU_OSA UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS L2 ${MSC_LIB} ${RAL_LIB} ${NAS_UE_LIB} ${ITTI_LIB} ${MIH_LIB}
-Wl,--end-group )
target_link_libraries (lte-softmodem ${LIBXML2_LIBRARIES})
-target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${XFORMS_LIBRARIES} )
+target_link_libraries (lte-softmodem pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} )
target_link_libraries (lte-softmodem ${LIBBOOST_LIBRARIES})
+target_link_libraries (lte-softmodem ${LIB_LMS_LIBRARIES})
# lte-softmodem-nos1 is both eNB and UE implementation
###################################################
@@ -1458,6 +1548,7 @@ add_executable(lte-softmodem-nos1
#${OPENAIR2_DIR}/RRC/NAS/rb_config.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${HW_SOURCE}
+ ${TRANSPORT_SOURCE}
${RTAI_SOURCE}
${XFORMS_SOURCE}
${XFORMS_SOURCE_SOFTMODEM}
@@ -1468,38 +1559,43 @@ target_link_libraries (lte-softmodem-nos1
-Wl,--end-group )
target_link_libraries (lte-softmodem-nos1 ${LIBXML2_LIBRARIES})
-target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${XFORMS_LIBRARIES} )
+target_link_libraries (lte-softmodem-nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib} ${XFORMS_LIBRARIES} )
target_link_libraries (lte-softmodem-nos1 ${LIBBOOST_LIBRARIES})
-
-
+target_link_libraries (lte-softmodem-nos1 ${LIB_LMS_LIBRARIES})
# rrh
################################
-set(DRIVER2013)
-
-#Note: only on RF type is currently supported for RRH
+#Note: only one RF type (USRP) is currently supported for RRH
add_executable(rrh_gw
${OPENAIR_TARGETS}/RT/USER/rrh_gw.c
${OPENAIR_TARGETS}/RT/USER/eNB_transport_IQ.c
${OPENAIR_TARGETS}/RT/USER/UE_transport_IQ.c
${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c
${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c
- ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
${HW_SOURCE}
+ ${TRANSPORT_SOURCE}
)
-# assert and common_lib.h
-target_include_directories(rrh_gw PRIVATE ${OPENAIR_DIR}/common/utils/itti ${OPENAIR_TARGETS}/ARCH/COMMON ${OPENAIR_TARGETS}/ARCH/ETHERNET/USERSPACE/LIB/ )
-
+target_include_directories(rrh_gw PRIVATE ${OPENAIR_DIR}/common/utils/itti)
target_link_libraries(rrh_gw
-Wl,--start-group
UTIL LFDS
-Wl,--end-group )
target_link_libraries (rrh_gw rt pthread m )
-target_link_libraries (rrh_gw ${option_HW_lib} ${LIBBOOST_LIBRARIES} )
+target_link_libraries (rrh_gw ${option_HW_lib} ${option_TP_lib} ${LIBBOOST_LIBRARIES} )
+target_link_libraries (rrh_gw ${LIB_LMS_LIBRARIES})
-#Message("-- default_HW_lib=ETHERNET") # only in case of RRH
Message("-- option_HW_lib=${option_HW_lib}")
Message("-- HW_SOURCE=${HW_SOURCE}")
+Message("-- option_TP_lib=${option_TP_lib}")
+Message("-- TRANSPORT_SOURCE=${TRANSPORT_SOURCE}")
+
+if (${RF_BOARD} STREQUAL "OAI_LMSSDR")
+ add_dependencies(lte-softmodem LMS7002M LMS_SDR Si5351C)
+ add_dependencies(lte-softmodem-nos1 LMS7002M LMS_SDR Si5351C)
+ add_dependencies(rrh_gw LMS7002M LMS_SDR Si5351C)
+endif (${RF_BOARD} STREQUAL "OAI_LMSSDR")
+
+
# USIM process
#################
@@ -1550,6 +1646,7 @@ add_executable(oaisim
${GTPU_need_ITTI}
${OPENAIR_TARGETS}/COMMON/create_tasks.c
${HW_SOURCE}
+ ${TRANSPORT_SOURCE}
${XFORMS_SOURCE}
)
@@ -1561,7 +1658,7 @@ target_link_libraries (oaisim
-Wl,--end-group )
target_link_libraries (oaisim ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES})
-target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib}
+target_link_libraries (oaisim pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} sctp ${option_HW_lib} ${option_TP_lib}
${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES})
#Force link with forms, regardless XFORMS option
target_link_libraries (oaisim forms)
@@ -1588,6 +1685,7 @@ add_executable(oaisim_nos1
${OPENAIR2_DIR}/UTIL/OMG/sumo.c
${OPENAIR_TARGETS}/COMMON/create_tasks.c
${HW_SOURCE}
+ ${TRANSPORT_SOURCE}
${XFORMS_SOURCE}
)
target_include_directories(oaisim_nos1 PUBLIC ${OPENAIR_TARGETS}/SIMU/USER)
@@ -1597,7 +1695,7 @@ target_link_libraries (oaisim_nos1
-Wl,--end-group )
target_link_libraries (oaisim_nos1 ${LIBXML2_LIBRARIES} ${LAPACK_LIBRARIES})
-target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib}
+target_link_libraries (oaisim_nos1 pthread m ${CONFIG_LIBRARIES} rt crypt ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${option_HW_lib} ${option_TP_lib}
${ATLAS_LIBRARIES} ${XFORMS_LIBRARIES} ${OPENPGM_LIBRARIES})
#Force link with forms, regardless XFORMS option
target_link_libraries (oaisim_nos1 forms)
diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml
index 03f10ce578..037f5c8ee9 100644
--- a/cmake_targets/autotests/test_case_list.xml
+++ b/cmake_targets/autotests/test_case_list.xml
@@ -81,7 +81,8 @@
--eNB -w USRP -r Rel10 --noS1 -c
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/rb_tool
- $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/liboai_usrpdevif.so
@@ -122,7 +123,8 @@
--eNB -w BLADERF -r Rel10 --noS1 -c
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/rb_tool
- $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/liboai_bladerfdevif.so
@@ -138,10 +140,11 @@
Build lte_softmodem_noS1.ETHERNET.Rel10
$OPENAIR_DIR/cmake_targets/build_oai
- --eNB -w ETHERNET -r Rel10 --noS1 -c
+ --eNB -w None -t ETHERNET -r Rel10 --noS1 -c
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/lte-softmodem-nos1
$OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/rb_tool
- $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/CMakeFiles/nasmesh/nasmesh.ko
+ $OPENAIR_DIR/cmake_targets/lte_noS1_build_oai/build/liboai_eth_transpro.so
@@ -160,7 +163,8 @@
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w USRP -r Rel10 -c
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/liboai_usrpdevif.so
@@ -197,7 +201,8 @@
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -r Rel10 -c
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/liboai_bladerfdevif.so
@@ -213,8 +218,9 @@
Build lte_softmodem.ETHERNET.Rel10
$OPENAIR_DIR/cmake_targets/build_oai
- --eNB -w ETHERNET -r Rel10 -c
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ --eNB -w None -t ETHERNET -r Rel10 -c
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ $OPENAIR_DIR/cmake_targets/lte_build_oai/build/liboai_eth_transpro.so
@@ -261,11 +267,13 @@
compilation
- Build RRH Gateway
+ Build RRH Gateway for USRP(RF) + Ethernet (Transport)
$OPENAIR_DIR/cmake_targets/build_oai
- --RRH -w USRP -c
- $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw
+ --RRH -w USRP -t ETHERNET -c
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_usrpdevif.so
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_eth_transpro.so
@@ -278,14 +286,16 @@
compilation
- Build RRH Gateway
+ Build RRH Gateway for EXMIMO(RF) + Ethernet (Transport)
$OPENAIR_DIR/cmake_targets/build_oai
- --RRH -w EXMIMO -c
+ --RRH -w EXMIMO -t ETHNERNET -c
$OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw
$OPENAIR_DIR/cmake_targets/rrh_gw/build/CMakeFiles/openair_rf/openair_rf.ko
$OPENAIR_DIR/cmake_targets/rrh_gw/build/updatefw
- $OPENAIR_DIR/cmake_targets/rrh_gw/build/oarf_config_exmimo.oct
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/oarf_config_exmimo.oct
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_exmimodevif.so
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_eth_transpro.so
@@ -301,8 +311,10 @@
Build RRH Gateway
$OPENAIR_DIR/cmake_targets/build_oai
- --RRH -w BLADERF -c
- $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw
+ --RRH -w BLADERF -t ETHERNET -c
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/rrh_gw
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_bladerfdevif.so
+ $OPENAIR_DIR/cmake_targets/rrh_gw/build/liboai_eth_transpro.so
@@ -4622,7 +4634,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -4639,17 +4651,17 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -29
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -26
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
@@ -4698,7 +4710,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -4715,23 +4727,23 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -32
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -29
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
- True
+ False
/tmp
@@ -4773,7 +4785,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -4790,23 +4802,23 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -35
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -32
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
- True
+ False
/tmp
@@ -4848,7 +4860,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -4865,23 +4877,23 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -29
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -26
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
- True
+ False
/tmp
@@ -4922,7 +4934,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -4939,23 +4951,23 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -32
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -29
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
- True
+ False
/tmp
@@ -4996,7 +5008,7 @@
lte-softmodem
- calisson
+ mozart
stevens
amerique
390
@@ -5013,23 +5025,23 @@
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf frame_type \"FDD\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_rx 1
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf nb_antennas_tx 1
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -35
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.82/24\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth1\"
- targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.82/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf pdsch_referenceSignalPower -32
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1_MME \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1_MME \"192.168.12.111/24\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_INTERFACE_NAME_FOR_S1U \"eth0\"
+ targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_IPV4_ADDRESS_FOR_S1U \"192.168.12.111/24\"
targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf ENB_PORT_FOR_S1U 2152
$OPENAIR_DIR/cmake_targets/build_oai
--eNB -w BLADERF -x -c
sudo -E $OPENAIR_DIR/cmake_targets/tools/start_bladerf.py
- $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
+ sudo -E chrt -f 99 $OPENAIR_DIR/cmake_targets/lte_build_oai/build/lte-softmodem
-O $OPENAIR_DIR/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.tm1.bladerfx40.conf -W
- True
+ False
/tmp
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index c723d8d6dc..6300e9ec03 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -49,13 +49,14 @@ LOWLATENCY_FLAG_USER="False"
FORCE_LOWLATENCY_FLAG_USER=""
REL="Rel10"
HW="EXMIMO"
+TP="None"
NOS1=0
EPC=0
VERBOSE_COMPILE=0
CFLAGS_PROCESSOR_USER=""
RUN_GROUP=0
TEST_CASE_GROUP=""
-
+BUILD_DOXYGEN=0
trap handle_ctrl_c INT
function print_help() {
@@ -90,10 +91,13 @@ Options
default is Rel10,
Rel8 limits the implementation to 3GPP Release 8 version
-w | --hardware
- EXMIMO (Default), USRP, BLADERF, ETHERNET, None
+ EXMIMO (Default), USRP, BLADERF, LMSSDR, None
Adds this RF board support (in external packages installation and in compilation)
+-t | --transport protocol
+ ETHERNET , None
+ Adds this trasport protocol support in compilation
--oaisim
- Makes the oaisim simulator. Hardware will be defaulted to "NONE".
+ Makes the oaisim simulator. Hardware will be defaulted to "None".
--phy_simulators
Makes the unitary tests Layer 1 simulators
--core_simulators
@@ -115,6 +119,8 @@ Options
Shows detailed compilation instructions in makefile
--cflags_processor
Manually Add CFLAGS of processor if they are not detected correctly by script. Only add these flags if you know your processor supports them. Example flags: -msse3 -msse4.1 -msse4.2 -mavx2
+--build-doxygen
+ Builds doxygen based documentation.
--disable-deadline
Disables deadline scheduler of Linux kernel (>=3.14.x).
--enable-deadline
@@ -170,20 +176,35 @@ function main() {
shift;;
-r | --3gpp-release)
REL=$2
- echo_info "setting release to: $REL"
+ echo_info "Setting release to: $REL"
shift 2;;
-w | --hardware)
HW="$2" #"${i#*=}"
- # Use OAI_USRP as the key word USRP is used inside UHD driver
- if [ "$HW" == "USRP" ] ; then
- HW="OAI_USRP"
- fi
- if [ "$HW" == "BLADERF" ] ; then
- HW="OAI_BLADERF"
- fi
- echo_info "setting hardware to: $HW"
+ # 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
+ echo_fatal "Unknown HW type $HW will exit..."
+ else
+ if [ "$HW" == "USRP" ] ; then
+ HW="OAI_USRP"
+ fi
+ if [ "$HW" == "BLADERF" ] ; then
+ HW="OAI_BLADERF"
+ fi
+ if [ "$HW" == "LMSSDR" ] ; then
+ HW="OAI_LMSSDR"
+ fi
+ echo_info "Setting hardware to: $HW"
+ fi
shift 2;;
- --oaisim)
+ -t | --transport_protocol)
+ TP="$2" #"${i#*=}"
+ if [ "$TP" != "ETHERNET" -a "$TP" != "None" ] ; then
+ echo_fatal "Unknown TP type $TP will exit..."
+ else
+ echo_info "Setting transport protocol to: $TP"
+ fi
+ shift 2;;
+ --oaisim)
oaisim=1
echo_info "Will compile oaisim and drivers nasmesh, ..."
shift;;
@@ -205,7 +226,7 @@ function main() {
echo_info "executing test cases only in group: $TEST_CASE_GROUP"
shift 2;;
-V | --vcd)
- echo_info "setting gtk-wave output"
+ echo_info "Setting gtk-wave output"
VCD_TIMING=1
EXE_ARGUMENTS="$EXE_ARGUMENTS -V"
shift;;
@@ -228,8 +249,12 @@ function main() {
shift;;
--cflags_processor)
CFLAGS_PROCESSOR_USER=$2
- echo_info "setting CPU FLAGS from USER to: $CFLAGS_PROCESSOR_USER"
+ echo_info "Setting CPU FLAGS from USER to: $CFLAGS_PROCESSOR_USER"
shift 2;;
+ --build-doxygen)
+ BUILD_DOXYGEN=1
+ echo_info "Will build doxygen support"
+ shift;;
--disable-deadline)
FORCE_LOWLATENCY_FLAG_USER="False"
echo_info "Disabling the usage of deadline scheduler"
@@ -238,7 +263,6 @@ function main() {
FORCE_LOWLATENCY_FLAG_USER="True"
echo_info "Enabling the usage of deadline scheduler"
shift 1;;
-
-h | --help)
print_help
exit 1;;
@@ -248,7 +272,37 @@ function main() {
break;;
esac
done
+
+ #########################################################
+ # check validity of HW and TP parameters for RRH and eNB
+ #########################################################
+ # to be discussed
+
+ if [ "$eNB" = "1" ] ; then
+ if [ "$HW" = "None" -a "$TP" = "None" ] ; then
+ echo_fatal "Define a local radio head (e.g. -w EXMIMO) or a transport protocol (e.g. -t ETHERNET) to communicate with a remote radio head!"
+ fi
+ if [ "$HW" != "None" -a "$TP" != "None" ] ; then
+ echo_fatal "Currently eNB can not support simultaniously local and remote radio heads!!"
+ fi
+ if [ "$HW" = "None" ] ; then
+ echo_info "No radio head has been selected (HW set to $HW)"
+ fi
+ if [ "$TP" = "None" ] ; then
+ echo_info "No transport protocol has been selected (TP set to $TP)"
+ fi
+ fi
+
+ if [ "$RRH" = "1" ] ; then
+ if [ "$TP" = "None" ] ; then
+ echo_fatal "A transport protocol (e.g. -t ETHERNET) must be defined!"
+ fi
+ 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,
#By default: BLADERF: enable,
@@ -262,6 +316,8 @@ function main() {
LOWLATENCY_FLAG_USER="False"
elif [ "$HW" = "OAI_BLADERF" ] ; then
LOWLATENCY_FLAG_USER="False"
+ elif [ "$HW" = "OAI_LMSSDR" ] ; then
+ LOWLATENCY_FLAG_USER="False"
elif [ "$HW" = "None" ] ; then
LOWLATENCY_FLAG_USER="False"
else
@@ -274,6 +330,7 @@ function main() {
echo_info "Flags for Deadline scheduler: $LOWLATENCY_FLAG_USER"
+
############################################
# setting and printing OAI envs, we should check here
############################################
@@ -312,7 +369,7 @@ function main() {
check_install_usrp_uhd_driver
fi
if [ "$HW" == "OAI_BLADERF" ] ; then
- echo_info "installing packages for BALDERF support"
+ echo_info "installing packages for BLADERF support"
check_install_bladerf_driver
fi
fi
@@ -323,9 +380,11 @@ function main() {
fi
if [ "$oaisim" = "1" ] ; then
- if [ "$HW" != "ETHERNET" ] ; then
- HW="NONE"
- fi
+ #to be discussed
+ # there is no RF device and no transport protocol
+ HW="None"
+ TP="None"
+
if [ "$XFORMS" == "True" ] ; then
PRINT_STATS="True"
fi
@@ -359,7 +418,8 @@ function main() {
echo "set ( RRC_ASN1_VERSION \"${REL}\")" >> $cmake_file
echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file
echo "set ( RF_BOARD \"${HW}\")" >> $cmake_file
- echo "set(PACKAGE_NAME \"${lte_exec}\")" >> $cmake_file
+ echo "set ( TRANSP_PRO \"${TP}\")" >> $cmake_file
+ echo "set(PACKAGE_NAME \"${lte_exec}\")" >> $cmake_file
echo "set (LOWLATENCY \"${LOWLATENCY_FLAG_USER}\" )" >>$cmake_file
echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file
cd $DIR/$lte_build_dir/build
@@ -565,33 +625,124 @@ function main() {
fi
# RRH compilation
- ##################
+ #####################
if [ "$RRH" = "1" ] ; then
- echo_info "Compiling RRH"
- if [ $HW == "ETHERNET" ] ; then
- echo_info "RF frontend for RRH is not defined. This mode is used for testing (loopback)."
- elif [ $HW != "EXMIMO" -a $HW != "OAI_USRP" -a $HW != "OAI_BLADERF" ] ; then
- echo_fatal "Hardware not defined ($HW)"
- fi
- cmake_file=$DIR/rrh_gw/CMakeLists.txt
- echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file
- echo "set(ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file
- echo "set(ENABLE_ITTI False )" >> $cmake_file
- echo "set(RF_BOARD \"${HW}\")" >> $cmake_file
- echo 'set(PACKAGE_NAME "\"rrh_gw\"")' >> $cmake_file
- echo "set(LOWLATENCY \"${LOWLATENCY_FLAG_USER}\")" >>$cmake_file
- echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file
- [ "$CLEAN" = "1" ] && rm -rf $DIR/rrh_gw/build
- mkdir -p $DIR/rrh_gw/build
- cd $DIR/rrh_gw/build
+ rrh_exec=rrh_gw
+ rrh_build_dir=rrh_gw
+
+ echo_info "Compiling $rrh_exec ..."
+
+ [ "$CLEAN" = "1" ] && rm -rf $DIR/rrh_gw/build
+ mkdir -p $DIR/$rrh_build_dir/build
+ cmake_file=$DIR/$rrh_build_dir/CMakeLists.txt
+ echo "cmake_minimum_required(VERSION 2.8)" > $cmake_file
+ echo "set(ENABLE_VCD_FIFO $VCD_TIMING )" >> $cmake_file
+ echo "set(ENABLE_ITTI False )" >> $cmake_file
+ echo "set(RF_BOARD \"${HW}\")" >> $cmake_file
+ echo "set(TRANSP_PRO \"${TP}\")" >> $cmake_file
+ echo 'set(PACKAGE_NAME "\"rrh_gw\"")' >> $cmake_file
+ echo "set (LOWLATENCY \"${LOWLATENCY_FLAG_USER}\" )" >>$cmake_file
+ echo 'include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)' >> $cmake_file
+ cd $DIR/$rrh_build_dir/build
+ cmake ..
+ compilations \
+ rrh_gw rrh_gw \
+ rrh_gw $dbin/rrh_gw
+
+ fi
+
+ # build RF device and transport protocol libraries
+ #####################################
+ if [ "$eNB" = "1" -o "$RRH" = "1" ] ; then
+
+ if [ "$eNB" = "1" ] ; then
+ build_dir=$lte_build_dir
+ else
+ build_dir=$rrh_build_dir
+ fi
+
+ # build RF device libraries (currently EXMIMO is not complied with the rest of HW targets)
+ if [ "$HW" != "None" ] ; then
+ rm -f liboai_device.so
+ rm -f $dbin/liboai_device.so
+
+
+ # link liboai_device.so with the selected RF device library
+ if [ "$HW" == "EXMIMO" ] ; then
+
+ #add exmimo compilation
+ #TODO EXMIMO library support
+
+ echo_info "liboai_device.so is linked to EXMIMO device library"
+ elif [ "$HW" == "OAI_USRP" ] ; then
+ if [ -d "/usr/include/uhd" ] ; then
+ compilations \
+ $build_dir oai_usrpdevif \
+ liboai_usrpdevif.so $dbin/liboai_usrpdevif.so.$REL
+ fi
+
+ ln -s liboai_usrpdevif.so liboai_device.so
+ ln -s $dbin/liboai_usrpdevif.so.$REL $dbin/liboai_device.so
+ echo_info "liboai_device.so is linked to USRP device library"
+ elif [ "$HW" == "OAI_BLADERF" ] ; then
+ if [ -f "/usr/include/libbladeRF.h" ] ; then
+ compilations \
+ $build_dir oai_bladerfdevif \
+ liboai_bladerfdevif.so $dbin/liboai_bladerfdevif.so.$REL
+ fi
+
+ ln -s liboai_bladerfdevif.so liboai_device.so
+ ln -s $dbin/liboai_bladerfdevif.so.$REL $dbin/liboai_device.so
+ echo_info "liboai_device.so is linked to BLADERF device library"
+ elif [ "$HW" == "OAI_LMSSDR" ] ; then
+# if [ -f "/usr/include/libbladeRF.h" ] ; then
+ compilations \
+ $build_dir oai_lmssdrdevif \
+ liboai_lmssdrdevif.so $dbin/liboai_lmssdrdevif.so.$REL
+# fi
+
+ ln -s liboai_lmssdrdevif.so liboai_device.so
+ ln -s $dbin/liboai_lmssdrdevif.so.$REL $dbin/liboai_device.so
+ echo_info "liboai_device.so is linked to LMSSDR device library"
+ else
+ echo_info "liboai_device.so is not linked to any device library"
+ fi
+ fi
+
+ # build trasport protocol libraries (currently only ETHERNET is available)
+ if [ "$TP" != "None" ] ; then
+ rm -f liboai_transpro.so
+ rm -f $dbin/liboai_transpro.so
+
+ if [ "$TP" == "ETHERNET" ] ; then
+ compilations \
+ $build_dir oai_eth_transpro \
+ liboai_eth_transpro.so $dbin/liboai_eth_transpro.so.$REL
+ ln -s liboai_eth_transpro.so liboai_transpro.so
+ ln -s $dbin/liboai_eth_transpro.so.$REL $dbin/liboai_transpro.so
+ echo_info "liboai_transpro.so is linked with ETHERNET library"
+ fi
+ fi
+fi
+
+
+ # Doxygen Support
+ #####################
+ if [ "$BUILD_DOXYGEN" = "1" ] ;then
+ doxygen_log=$OPENAIR_DIR/cmake_targets/log/doxygen.log
+ echo_info "Building doxygen based documentation. The documentation file is located here: $OPENAIR_DIR/targets/DOCS/html/index.html"
+ echo_info "Doxygen Generation log is located here: $doxygen_log"
+ echo_info "Generating doxygen files....please wait"
+ (
+ [ "$CLEAN" = "1" ] && rm -rf $OPENAIR_DIR/cmake_targets/doxygen/build
+ mkdir -p $OPENAIR_DIR/cmake_targets/doxygen/build
+ cd $OPENAIR_DIR/cmake_targets/doxygen/build
cmake ..
- compilations \
- rrh_gw rrh_gw \
- rrh_gw $dbin/rrh_gw
+ make doc
+ ) >& $doxygen_log
fi
-
# Auto-tests
#####################
if [ "$OAI_TEST" = "1" ]; then
diff --git a/cmake_targets/rrh_gw/CMakeLists.txt b/cmake_targets/rrh_gw/CMakeLists.txt
deleted file mode 100644
index 9ff1437f0c..0000000000
--- a/cmake_targets/rrh_gw/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-set(ENABLE_VCD_FIFO False )
-set(ENABLE_ITTI False )
-set(RF_BOARD "ETHERNET")
-set(PACKAGE_NAME "\"rrh_gw\"")
-include(${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt)
diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper
index 496096e972..c8adf45257 100755
--- a/cmake_targets/tools/build_helper
+++ b/cmake_targets/tools/build_helper
@@ -180,7 +180,7 @@ check_install_bladerf_driver(){
$SUDO apt-get install -y bladerf libbladerf-dev
$SUDO apt-get install -y bladerf-firmware-fx3
$SUDO apt-get install -y bladerf-fpga-hostedx40
- bladeRF-cli --flash-firmware /usr/share/Nuand/bladeRF/bladeRF_fw.img
+ $SUDO bladeRF-cli --flash-firmware /usr/share/Nuand/bladeRF/bladeRF_fw.img
}
check_install_additional_tools (){
@@ -380,3 +380,21 @@ done
}
+# get from http://www.linuxjournal.com/content/validating-ip-address-bash-script
+validate_ip() {
+
+local ip=$1
+local stat=1
+
+if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
+ OIFS=$IFS
+ IFS='.'
+ ip=($ip)
+ IFS=$OIFS
+ [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
+ && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
+ stat=$?
+fi
+
+return $stat
+}
\ No newline at end of file
diff --git a/openair1/PHY/LTE_REFSIG/primary_synch.h b/openair1/PHY/LTE_REFSIG/primary_synch.h
index f9cf6fc171..717f2e552c 100644
--- a/openair1/PHY/LTE_REFSIG/primary_synch.h
+++ b/openair1/PHY/LTE_REFSIG/primary_synch.h
@@ -1,31 +1,3 @@
-/*******************************************************************************
- OpenAirInterface
- Copyright(c) 1999 - 2014 Eurecom
-
- OpenAirInterface is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
-
- OpenAirInterface is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with OpenAirInterface.The full GNU General Public License is
- included in this distribution in the file called "COPYING". If not,
- see .
-
- Contact Information
- OpenAirInterface Admin: openair_admin@eurecom.fr
- OpenAirInterface Tech : openair_tech@eurecom.fr
- OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
-
- Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
-
- *******************************************************************************/
short primary_synch0[144] = {0,0,0,0,0,0,0,0,0,0,32767,0,-26120,-19785,11971,-30502,-24020,-22288,32117,6492,31311,9658,-16384,-28378,25100,-21063,-7292,-31946,20429,25618,14948,29158,11971,-30502,31311,9658,25100,-21063,-16384,28377,-24020,22287,32117,6492,-7292,31945,20429,25618,-26120,-19785,-16384,-28378,-16384,28377,-26120,-19785,-32402,4883,31311,-9659,32117,6492,-7292,-31946,32767,-1,25100,-21063,-24020,22287,-32402,4883,-32402,4883,-24020,22287,25100,-21063,32767,-1,-7292,-31946,32117,6492,31311,-9659,-32402,4883,-26120,-19785,-16384,28377,-16384,-28378,-26120,-19785,20429,25618,-7292,31945,32117,6492,-24020,22287,-16384,28377,25100,-21063,31311,9658,11971,-30502,14948,29158,20429,25618,-7292,-31946,25100,-21063,-16384,-28378,31311,9658,32117,6492,-24020,-22288,11971,-30502,-26120,-19785,32767,0,0,0,0,0,0,0,0,0,0,0};
short primary_synch1[144] = {0,0,0,0,0,0,0,0,0,0,32767,0,-31754,-8086,-24020,-22288,2448,32675,-26120,19784,27073,18458,-16384,28377,25100,21062,-29523,14217,-7292,31945,-13477,-29868,-24020,-22288,27073,18458,25100,21062,-16384,-28378,2448,-32676,-26120,19784,-29523,-14218,-7292,31945,-31754,-8086,-16384,28377,-16384,-28378,-31754,-8086,31311,-9659,27073,-18459,-26120,19784,-29523,14217,32767,-1,25100,21062,2448,-32676,31311,-9659,31311,-9659,2448,-32676,25100,21062,32767,0,-29523,14217,-26120,19784,27073,-18459,31311,-9659,-31754,-8086,-16384,-28378,-16384,28377,-31754,-8086,-7292,31945,-29523,-14218,-26120,19784,2448,-32676,-16384,-28378,25100,21062,27073,18458,-24020,-22288,-13477,-29868,-7292,31945,-29523,14217,25100,21062,-16384,28377,27073,18458,-26120,19784,2448,32675,-24020,-22288,-31754,-8086,32767,0,0,0,0,0,0,0,0,0,0,0};
short primary_synch2[144] = {0,0,0,0,0,0,0,0,0,0,32767,0,-31754,8085,-24020,22287,2448,-32676,-26120,-19785,27073,-18459,-16384,-28378,25100,-21063,-29523,-14218,-7292,-31946,-13477,29867,-24020,22287,27073,-18459,25100,-21063,-16384,28377,2448,32675,-26120,-19785,-29523,14217,-7292,-31946,-31754,8085,-16384,-28378,-16384,28377,-31754,8085,31311,9658,27073,18458,-26120,-19785,-29523,-14218,32767,0,25100,-21063,2448,32675,31311,9658,31311,9658,2448,32675,25100,-21063,32767,0,-29523,-14218,-26120,-19785,27073,18458,31311,9658,-31754,8085,-16384,28377,-16384,-28378,-31754,8085,-7292,-31946,-29523,14217,-26120,-19785,2448,32675,-16384,28377,25100,-21063,27073,-18459,-24020,22287,-13477,29867,-7292,-31946,-29523,-14218,25100,-21063,-16384,-28378,27073,-18459,-26120,-19785,2448,-32676,-24020,22287,-31754,8085,32767,-1,0,0,0,0,0,0,0,0,0,0};
diff --git a/openair1/PHY/LTE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_TRANSPORT/initial_sync.c
index 5c6b479b20..b8be6305de 100644
--- a/openair1/PHY/LTE_TRANSPORT/initial_sync.c
+++ b/openair1/PHY/LTE_TRANSPORT/initial_sync.c
@@ -48,7 +48,7 @@
#include "gain_control.h"
#endif
-#if defined(OAI_USRP) || defined(EXMIMO)
+#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_LMSSDR)
#include "common_lib.h"
extern openair0_config_t openair0_cfg[];
#endif
@@ -291,17 +291,10 @@ int initial_sync(PHY_VARS_UE *phy_vars_ue, runmode_t mode)
frame_parms->Ncp=NORMAL;
frame_parms->frame_type=FDD;
init_frame_parms(frame_parms,1);
-
- // write_output("rxdata0.m","rxd0",phy_vars_ue->lte_ue_common_vars.rxdata[0],10*frame_parms->samples_per_tti,1,1);
-
- /*#ifdef OAI_USRP
- for (aarx = 0; aarxnb_antennas_rx;aarx++) {
- rxdata128 = (__m128i*)phy_vars_ue->lte_ue_common_vars.rxdata[aarx];
- for (i=0; i<(frame_parms->samples_per_tti*10)>>2; i++) {
- rxdata128[i] = _mm_srai_epi16(rxdata128[i],4);
- }
- }
- #endif*/
+ /*
+ write_output("rxdata0.m","rxd0",phy_vars_ue->lte_ue_common_vars.rxdata[0],10*frame_parms->samples_per_tti,1,1);
+ exit(-1);
+ */
sync_pos = lte_sync_time(phy_vars_ue->lte_ue_common_vars.rxdata,
frame_parms,
(int *)&phy_vars_ue->lte_ue_common_vars.eNb_id);
@@ -336,9 +329,11 @@ int initial_sync(PHY_VARS_UE *phy_vars_ue, runmode_t mode)
#else
#ifndef OAI_USRP
- #ifndef OAI_BLADERF
+#ifndef OAI_BLADERF
+#ifndef OAI_LMSSDR
phy_adjust_gain(phy_vars_ue,0);
- #endif
+#endif
+#endif
#endif
#endif
@@ -569,7 +564,7 @@ int initial_sync(PHY_VARS_UE *phy_vars_ue, runmode_t mode)
phy_vars_ue->lte_frame_parms.phich_config_common.phich_duration,
phich_string[phy_vars_ue->lte_frame_parms.phich_config_common.phich_resource],
phy_vars_ue->lte_frame_parms.nb_antennas_tx_eNB);
-#if defined(OAI_USRP) || defined(EXMIMO)
+#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_LMSSDR)
LOG_I(PHY,"[UE %d] Frame %d Measured Carrier Frequency %.0f Hz (offset %d Hz)\n",
phy_vars_ue->Mod_id,
phy_vars_ue->frame_rx,
diff --git a/openair1/PHY/LTE_TRANSPORT/print_stats.c b/openair1/PHY/LTE_TRANSPORT/print_stats.c
index 54c32cdca6..4a953e71e0 100644
--- a/openair1/PHY/LTE_TRANSPORT/print_stats.c
+++ b/openair1/PHY/LTE_TRANSPORT/print_stats.c
@@ -50,7 +50,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)
+#if defined(OAI_USRP) || defined(EXMIMO) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
#include "common_lib.h"
extern openair0_config_t openair0_cfg[];
#endif
@@ -97,10 +97,10 @@ int dump_ue_stats(PHY_VARS_UE *phy_vars_ue, char* buffer, int length, runmode_t
#ifdef EXMIMO
len += sprintf(&buffer[len], "[UE PROC] RX Gain %d dB (LNA %d, vga %d dB)\n",phy_vars_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)
+#if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
len += sprintf(&buffer[len], "[UE PROC] RX Gain %d dB\n",phy_vars_ue->rx_total_gain_dB);
#endif
-#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
len += sprintf(&buffer[len], "[UE_PROC] Frequency offset %d Hz (%d), estimated carrier frequency %f Hz\n",phy_vars_ue->lte_ue_common_vars.freq_offset,openair_daq_vars.freq_offset,openair0_cfg[0].rx_freq[0]-phy_vars_ue->lte_ue_common_vars.freq_offset);
#endif
len += sprintf(&buffer[len], "[UE PROC] UE mode = %s (%d)\n",mode_string[phy_vars_ue->UE_mode[0]],phy_vars_ue->UE_mode[0]);
diff --git a/openair1/PHY/TOOLS/lte_phy_scope.c b/openair1/PHY/TOOLS/lte_phy_scope.c
index e507024c86..843a77fe62 100644
--- a/openair1/PHY/TOOLS/lte_phy_scope.c
+++ b/openair1/PHY/TOOLS/lte_phy_scope.c
@@ -88,7 +88,7 @@ FD_lte_phy_scope_enb *create_lte_phy_scope_enb( void )
fl_set_object_boxtype( fdui->rxsig_t, FL_EMBOSSED_BOX );
fl_set_object_color( fdui->rxsig_t, FL_BLACK, FL_RED );
fl_set_object_lcolor( fdui->rxsig_t, FL_WHITE ); // Label color
- fl_set_xyplot_ybounds(fdui->rxsig_t,30,70);
+ fl_set_xyplot_ybounds(fdui->rxsig_t,10,70);
// Time-domain channel response
fdui->chest_t = fl_add_xyplot( FL_NORMAL_XYPLOT, 410, 20, 370, 100, "Channel Impulse Response (samples, abs)" );
@@ -396,7 +396,7 @@ FD_lte_phy_scope_ue *create_lte_phy_scope_ue( void )
fl_set_object_boxtype( fdui->rxsig_t, FL_EMBOSSED_BOX );
fl_set_object_color( fdui->rxsig_t, FL_BLACK, FL_RED );
fl_set_object_lcolor( fdui->rxsig_t, FL_WHITE ); // Label color
- fl_set_xyplot_ybounds(fdui->rxsig_t,30,70);
+ fl_set_xyplot_ybounds(fdui->rxsig_t,10,70);
// Time-domain channel response
fdui->chest_t = fl_add_xyplot( FL_NORMAL_XYPLOT, 410, 20, 370, 100, "Channel Impulse Response (samples, abs)" );
diff --git a/openair1/PHY/defs.h b/openair1/PHY/defs.h
index dc0b79e471..f308c0500a 100755
--- a/openair1/PHY/defs.h
+++ b/openair1/PHY/defs.h
@@ -76,6 +76,13 @@
#define openair_free(y,x) free((y))
#define PAGE_SIZE 4096
+//#ifdef SHRLIBDEV
+//extern int rxrescale;
+//#define RX_IQRESCALELEN rxrescale
+//#else
+//#define RX_IQRESCALELEN 15
+//#endif
+
//! \brief Allocate \c size bytes of memory on the heap with alignment 16 and zero it afterwards.
//! If no more memory is available, this function will terminate the program with an assertion error.
static inline void* malloc16_clear( size_t size )
diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h
index 4b0edcff29..388687e97b 100755
--- a/openair1/PHY/impl_defs_top.h
+++ b/openair1/PHY/impl_defs_top.h
@@ -44,7 +44,14 @@
/** @defgroup _ref_implementation_ OpenAirInterface LTE Implementation
* @{
- * @defgroup _PHY_RF_INTERFACE_ Generic PHY - RF Interface
+ * @defgroup _PHY_RF_INTERFACE_ PHY - RF Interface
+ * @ingroup _PHY_RF_INTERFACE_
+ * @{
+ * @defgroup _GENERIC_PHY_RF_INTERFACE_ Generic PHY - RF Interface
+ * @defgroup _USRP_PHY_RF_INTERFACE_ PHY - USRP RF Interface
+ * @defgroup _BLADERF_PHY_RF_INTERFACE_ PHY - BLADERF RF Interface
+ * @}
+ *
* @ingroup _ref_implementation_
* @{
* This module is responsible for defining the generic interface between PHY and RF Target
diff --git a/openair1/SCHED/phy_procedures_lte_ue.c b/openair1/SCHED/phy_procedures_lte_ue.c
index ef93068fb4..985cda147f 100755
--- a/openair1/SCHED/phy_procedures_lte_ue.c
+++ b/openair1/SCHED/phy_procedures_lte_ue.c
@@ -121,7 +121,7 @@ extern int rx_sig_fifo;
#endif
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
#endif
@@ -197,7 +197,7 @@ void dump_dlsch_SI(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t subframe)
exit(-1);
}
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
//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)
@@ -669,7 +669,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
uint8_t ack_status=0;
int8_t Po_PUCCH;
int32_t ulsch_start=0;
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
int overflow=0;
int k,l;
#endif
@@ -969,7 +969,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
#endif
phy_vars_ue->tx_total_RE = nb_rb*12;
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
tx_amp = get_tx_amp(phy_vars_ue->tx_power_dBm,
phy_vars_ue->tx_power_max_dBm,
phy_vars_ue->lte_frame_parms.N_RB_UL,
@@ -1065,7 +1065,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
#endif
phy_vars_ue->tx_total_RE = 12;
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
tx_amp = get_tx_amp(Po_PUCCH,
phy_vars_ue->tx_power_max_dBm,
phy_vars_ue->lte_frame_parms.N_RB_UL,
@@ -1128,7 +1128,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
#endif
phy_vars_ue->tx_total_RE = 12;
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
tx_amp = get_tx_amp(Po_PUCCH,
phy_vars_ue->tx_power_max_dBm,
phy_vars_ue->lte_frame_parms.N_RB_UL,
@@ -1230,7 +1230,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
if (abstraction_flag == 0) {
nsymb = (frame_parms->Ncp == 0) ? 14 : 12;
-#if defined(EXMIMO) || defined(OAI_USRP) //this is the EXPRESS MIMO case
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)//this is the EXPRESS MIMO case
ulsch_start = (phy_vars_ue->rx_offset+subframe_tx*frame_parms->samples_per_tti-
openair_daq_vars.timing_advance-
phy_vars_ue->timing_advance-
@@ -1257,7 +1257,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
for (aa=0; aanb_antennas_tx; aa++) {
if (frame_parms->Ncp == 1)
PHY_ofdm_mod(&phy_vars_ue->lte_ue_common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size],
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
dummy_tx_buffer,
#else
&phy_vars_ue->lte_ue_common_vars.txdata[aa][ulsch_start],
@@ -1268,7 +1268,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
CYCLIC_PREFIX);
else
normal_prefix_mod(&phy_vars_ue->lte_ue_common_vars.txdataF[aa][subframe_tx*nsymb*frame_parms->ofdm_symbol_size],
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
dummy_tx_buffer,
#else
&phy_vars_ue->lte_ue_common_vars.txdata[aa][ulsch_start],
@@ -1289,7 +1289,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
}
*/
#ifndef OFDMA_ULSCH
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
apply_7_5_kHz(phy_vars_ue,dummy_tx_buffer,0);
apply_7_5_kHz(phy_vars_ue,dummy_tx_buffer,1);
#else
@@ -1304,7 +1304,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
*/
#endif
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
overflow = ulsch_start - 9*frame_parms->samples_per_tti;
//if ((slot_tx==4) && (aa==0)) printf("ulsch_start %d, overflow %d\n",ulsch_start,overflow);
@@ -1404,7 +1404,7 @@ void phy_procedures_UE_TX(PHY_VARS_UE *phy_vars_ue,uint8_t eNB_id,uint8_t abstra
phy_vars_ue->tx_total_RE = 96;
-#if defined(EXMIMO) || defined(OAI_USRP)
+#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
phy_vars_ue->lte_ue_prach_vars[eNB_id]->amp = get_tx_amp(phy_vars_ue->tx_power_dBm,
phy_vars_ue->tx_power_max_dBm,
phy_vars_ue->lte_frame_parms.N_RB_UL,
@@ -1553,9 +1553,11 @@ void lte_ue_measurement_procedures(uint16_t l, PHY_VARS_UE *phy_vars_ue,uint8_t
#else
#ifndef OAI_USRP
- #ifndef OAI_BLADERF
+#ifndef OAI_BLADERF
+#ifndef OAI_LMSSDR
phy_adjust_gain (phy_vars_ue,0);
- #endif
+#endif
+#endif
#endif
#endif
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GAIN_CONTROL, VCD_FUNCTION_OUT);
diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c
index fbb88bf052..2c3d0848c2 100644
--- a/openair1/SIMULATION/LTE_PHY/dlsim.c
+++ b/openair1/SIMULATION/LTE_PHY/dlsim.c
@@ -656,7 +656,17 @@ int main(int argc, char **argv)
printf("dual_stream_UE=%d\n", dual_stream_UE);
}
- lte_param_init(n_tx,n_rx,transmission_mode,extended_prefix_flag,frame_type,Nid_cell,tdd_config,N_RB_DL,threequarter_fs,osf,perfect_ce);
+ lte_param_init(n_tx,
+ n_rx,
+ transmission_mode,
+ extended_prefix_flag,
+ frame_type,
+ Nid_cell,
+ tdd_config,
+ N_RB_DL,
+ threequarter_fs,
+ osf,
+ perfect_ce);
diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c
index a72f2ad6c5..463c74c123 100644
--- a/openair1/SIMULATION/LTE_PHY/ulsim.c
+++ b/openair1/SIMULATION/LTE_PHY/ulsim.c
@@ -194,6 +194,7 @@ int main(int argc, char **argv)
int nb_rb_set = 0;
int sf;
+ int threequarter_fs=0;
opp_enabled=1; // to enable the time meas
cpu_freq_GHz = (double)get_cpu_freq_GHz();
@@ -203,7 +204,7 @@ int main(int argc, char **argv)
logInit();
- while ((c = getopt (argc, argv, "hapZbm:n:Y:X:x:s:w:e:q:d:D:O:c:r:i:f:y:c:oA:C:R:g:N:l:S:T:QB:PI:L")) != -1) {
+ while ((c = getopt (argc, argv, "hapZEbm:n:Y:X:x:s:w:e:q:d:D:O:c:r:i:f:y:c:oA:C:R:g:N:l:S:T:QB:PI:L")) != -1) {
switch (c) {
case 'a':
channel_model = AWGN;
@@ -373,6 +374,10 @@ int main(int argc, char **argv)
cyclic_shift = atoi(optarg);
break;
+ case 'E':
+ threequarter_fs=1;
+ break;
+
case 'N':
N0 = atoi(optarg);
break;
@@ -470,6 +475,7 @@ int main(int argc, char **argv)
0,
tdd_config,
N_RB_DL,
+ threequarter_fs,
osf,
0);
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index 07e0ffa640..4c532285f2 100755
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -170,6 +170,18 @@
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U "ENB_IPV4_ADDRESS_FOR_S1U"
#define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U"
+#define ENB_CONFIG_STRING_RRH_GW_CONFIG "rrh_gw_config"
+#define ENB_CONFIG_STRING_RRH_GW_LOCAL_IF_NAME "local_if_name"
+#define ENB_CONFIG_STRING_RRH_GW_LOCAL_ADDRESS "local_address"
+#define ENB_CONFIG_STRING_RRH_GW_REMOTE_ADDRESS "remote_address"
+#define ENB_CONFIG_STRING_RRH_GW_LOCAL_PORT "local_port"
+#define ENB_CONFIG_STRING_RRH_GW_REMOTE_PORT "remote_port"
+#define ENB_CONFIG_STRING_RRH_GW_ACTIVE "rrh_gw_active"
+#define ENB_CONFIG_STRING_RRH_GW_TRANSPORT_PREFERENCE "tr_preference"
+#define ENB_CONFIG_STRING_RRH_GW_RF_TARGET_PREFERENCE "rf_preference"
+#define ENB_CONFIG_STRING_RRH_GW_IQ_TXSHIFT "iq_txshift"
+#define ENB_CONFIG_STRING_RRH_GW_TX_SAMPLE_ADVANCE "tx_sample_advance"
+#define ENB_CONFIG_STRING_RRH_GW_TX_SCHEDULING_ADVANCE "tx_scheduling_advance"
#define ENB_CONFIG_STRING_ASN1_VERBOSITY "Asn1_verbosity"
#define ENB_CONFIG_STRING_ASN1_VERBOSITY_NONE "none"
@@ -274,6 +286,34 @@ static void enb_config_display(void)
} else {
printf( "\tMNC: \t%02"PRIu16":\n",enb_properties.properties[i]->mnc);
}
+
+ for (j=0; j< enb_properties.properties[i]->nb_rrh_gw; j++) {
+ if (enb_properties.properties[i]->rrh_gw_config[j].active == 1 ){
+ printf( "\n\tRRH GW %d config for eNB %u:\n\n", j, i);
+ printf( "\tinterface name : \t%s:\n",enb_properties.properties[i]->rrh_gw_if_name);
+ printf( "\tlocal address : \t%s:\n",enb_properties.properties[i]->rrh_gw_config[j].local_address);
+ printf( "\tlocal port : \t%d:\n",enb_properties.properties[i]->rrh_gw_config[j].local_port);
+ printf( "\tremote address : \t%s:\n",enb_properties.properties[i]->rrh_gw_config[j].remote_address);
+ printf( "\tremote port : \t%d:\n",enb_properties.properties[i]->rrh_gw_config[j].remote_port);
+ printf( "\ttx_scheduling_advance :\t%d:\n",enb_properties.properties[i]->rrh_gw_config[j].tx_scheduling_advance);
+ printf( "\ttx_sample_advance : \t%d:\n",enb_properties.properties[i]->rrh_gw_config[j].tx_sample_advance);
+ printf( "\tiq_txshift : \t%d:\n",enb_properties.properties[i]->rrh_gw_config[j].iq_txshift);
+ printf( "\ttransport : \t%s Ethernet:\n",(enb_properties.properties[i]->rrh_gw_config[j].raw == 1)? "RAW" : "UDP");
+ if (enb_properties.properties[i]->rrh_gw_config[j].exmimo == 1) {
+ printf( "\tRF target : \tEXMIMO:\n\n");
+ } else if (enb_properties.properties[i]->rrh_gw_config[j].usrp_b200 == 1) {
+ printf( "\tRF target : \tUSRP_B200:\n\n");
+ } else if (enb_properties.properties[i]->rrh_gw_config[j].usrp_x300 == 1) {
+ printf( "\tRF target : \tUSRP_X300:\n\n");
+ } else if (enb_properties.properties[i]->rrh_gw_config[j].bladerf == 1) {
+ printf( "\tRF target : \tBLADERF:\n\n");
+ } else if (enb_properties.properties[i]->rrh_gw_config[j].lmssdr == 1) {
+ printf( "\tRF target : \tLMSSDR:\n\n");
+ } else {
+ printf( "\tRF target : \tNONE:\n\n");
+ }
+ }
+ }
for (j=0; j< enb_properties.properties[i]->nb_cc; j++) {
printf( "\teutra band for CC %d: \t%"PRId16":\n",j,enb_properties.properties[i]->eutra_band[j]);
@@ -455,15 +495,18 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
config_setting_t *setting_srb1 = NULL;
config_setting_t *setting_mme_addresses = NULL;
config_setting_t *setting_mme_address = NULL;
+ config_setting_t *setting_rrh_gws = NULL;
+ config_setting_t *setting_rrh_gw = NULL;
config_setting_t *setting_enb = NULL;
config_setting_t *setting_otg = NULL;
- config_setting_t *subsetting_otg = NULL;
+ config_setting_t *subsetting_otg = NULL;
int num_enb_properties = 0;
int enb_properties_index = 0;
int num_enbs = 0;
int num_mme_address = 0;
- int num_otg_elements =0;
- int num_component_carriers =0;
+ int num_rrh_gw = 0;
+ int num_otg_elements = 0;
+ int num_component_carriers = 0;
int i = 0;
int j = 0;
int parse_errors = 0;
@@ -558,10 +601,21 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
libconfig_int my_int;
+
+ char* if_name = NULL;
char* ipv4 = NULL;
+ char* ipv4_remote = NULL;
char* ipv6 = NULL;
char* active = NULL;
char* preference = NULL;
+
+ char* tr_preference = NULL;
+ char* rf_preference = NULL;
+ libconfig_int tx_scheduling_advance = 0;
+ libconfig_int tx_sample_advance = 0;
+ libconfig_int iq_txshift = 0;
+ libconfig_int local_port = 0;
+ libconfig_int remote_port = 0;
const char* active_enb[MAX_ENB];
char* enb_interface_name_for_S1U = NULL;
char* enb_ipv4_address_for_S1U = NULL;
@@ -2136,6 +2190,97 @@ const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
}
}
+ // RRH Config
+ setting_rrh_gws = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_RRH_GW_CONFIG);
+ if ( setting_rrh_gws != NULL) {
+ num_rrh_gw = config_setting_length(setting_rrh_gws);
+ enb_properties.properties[enb_properties_index]->nb_rrh_gw = 0;
+
+ for (j = 0; j < num_rrh_gw; j++) {
+ setting_rrh_gw = config_setting_get_elem(setting_rrh_gws, j);
+
+ if ( !(
+ config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_LOCAL_IF_NAME, (const char **)&if_name)
+ && config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_LOCAL_ADDRESS, (const char **)&ipv4)
+ && config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_REMOTE_ADDRESS , (const char **)&ipv4_remote)
+ && config_setting_lookup_int(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_LOCAL_PORT, &local_port)
+ && config_setting_lookup_int(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_REMOTE_PORT, &remote_port)
+ && config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_ACTIVE, (const char **)&active)
+ && config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_TRANSPORT_PREFERENCE, (const char **)&tr_preference)
+ && config_setting_lookup_string(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_RF_TARGET_PREFERENCE, (const char **)&rf_preference)
+ && config_setting_lookup_int(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_IQ_TXSHIFT, &iq_txshift)
+ && config_setting_lookup_int(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_TX_SAMPLE_ADVANCE, &tx_sample_advance)
+ && config_setting_lookup_int(setting_rrh_gw, ENB_CONFIG_STRING_RRH_GW_TX_SCHEDULING_ADVANCE, &tx_scheduling_advance)
+ )
+ ) {
+ AssertError (0, parse_errors ++,
+ "Failed to parse eNB configuration file %s, %u th enb %u the RRH GW address !\n",
+ lib_config_file_name_pP, i, j);
+ continue; // FIXME will prevent segfaults below, not sure what happens at function exit...
+ }
+
+ enb_properties.properties[enb_properties_index]->nb_rrh_gw += 1;
+
+ enb_properties.properties[enb_properties_index]->rrh_gw_if_name = strdup(if_name);
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].local_address = strdup(ipv4);
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].remote_address = strdup(ipv4_remote);
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].local_port = local_port;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].remote_port = remote_port;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].iq_txshift = iq_txshift;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].tx_sample_advance = tx_sample_advance;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].tx_scheduling_advance= tx_scheduling_advance;
+
+ if (strcmp(active, "yes") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].active = 1;
+ }
+
+ if (strcmp(tr_preference, "udp") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].udp = 1;
+ } else if (strcmp(tr_preference, "raw") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].raw = 1;
+ } else {//if (strcmp(preference, "no") == 0)
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].udp = 1;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].raw = 1;
+ }
+
+ if (strcmp(rf_preference, "exmimo") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].exmimo = 1;
+ } else if (strcmp(rf_preference, "usrp_b200") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_b200 = 1;
+ } else if (strcmp(rf_preference, "usrp_x300") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_x300 = 1;
+ } else if (strcmp(rf_preference, "bladerf") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].bladerf = 1;
+ } else if (strcmp(rf_preference, "bladerf") == 0) {
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].lmssdr = 1;
+ } else {//if (strcmp(preference, "no") == 0)
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].exmimo = 1;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_b200 = 1;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_x300 = 1;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].bladerf = 1;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].lmssdr = 1;
+
+ }
+ }
+ } else {
+ enb_properties.properties[enb_properties_index]->nb_rrh_gw = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_if_name = "none";
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].local_address = "0.0.0.0";
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].remote_address = "0.0.0.0";
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].local_port= 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].remote_port= 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].active = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].udp = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].raw = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].tx_scheduling_advance = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].tx_sample_advance = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].iq_txshift = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].exmimo = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_b200 = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].usrp_x300 = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].bladerf = 0;
+ enb_properties.properties[enb_properties_index]->rrh_gw_config[j].lmssdr = 0;
+ }
// SCTP SETTING
enb_properties.properties[enb_properties_index]->sctp_out_streams = SCTP_OUT_STREAMS;
diff --git a/openair2/ENB_APP/enb_config.h b/openair2/ENB_APP/enb_config.h
index 113681dafe..422ef67cd3 100755
--- a/openair2/ENB_APP/enb_config.h
+++ b/openair2/ENB_APP/enb_config.h
@@ -78,6 +78,24 @@ typedef struct mme_ip_address_s {
char *ipv6_address;
} mme_ip_address_t;
+typedef struct rrh_gw_config_s {
+ unsigned udp:1;
+ unsigned raw:1;
+ unsigned active:1;
+ char *local_address;
+ char *remote_address;
+ uint16_t local_port;
+ uint16_t remote_port;
+ int tx_scheduling_advance;
+ int tx_sample_advance;
+ int iq_txshift;
+ unsigned exmimo:1;
+ unsigned usrp_b200:1;
+ unsigned usrp_x300:1;
+ unsigned bladerf:1;
+ unsigned lmssdr:1;
+} rrh_gw_config_t;
+
typedef struct Enb_properties_s {
/* Unique eNB_id to identify the eNB within EPC.
* For macro eNB ids this field should be 20 bits long.
@@ -203,6 +221,13 @@ typedef struct Enb_properties_s {
char *enb_interface_name_for_S1_MME;
in_addr_t enb_ipv4_address_for_S1_MME;
+
+ /* Nb of RRH to connect to */
+ uint8_t nb_rrh_gw;
+ char *rrh_gw_if_name;
+ /* List of MME to connect to */
+ rrh_gw_config_t rrh_gw_config[4];
+
// otg config
/* Nb of OTG elements */
uint8_t num_otg_elements;
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.c b/openair2/UTIL/LOG/vcd_signal_dumper.c
index 8dfbfd6ef5..31ce2e0d71 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.c
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.c
@@ -106,6 +106,9 @@ const char* eurecomVariablesNames[] = {
"lhw_cnt_tx",
"pck_rx",
"pck_tx",
+ "rx_seq_num",
+ "rx_seq_num_prv",
+ "tx_seq_num",
"cnt",
"dummy_dump",
"itti_send_msg",
diff --git a/openair2/UTIL/LOG/vcd_signal_dumper.h b/openair2/UTIL/LOG/vcd_signal_dumper.h
index 68257484f0..9ca55846fd 100644
--- a/openair2/UTIL/LOG/vcd_signal_dumper.h
+++ b/openair2/UTIL/LOG/vcd_signal_dumper.h
@@ -78,6 +78,9 @@ typedef enum {
VCD_SIGNAL_DUMPER_VARIABLES_TX_LHWCNT,
VCD_SIGNAL_DUMPER_VARIABLES_RX_PCK,
VCD_SIGNAL_DUMPER_VARIABLES_TX_PCK,
+ VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,
+ VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,
+ VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM,
VCD_SIGNAL_DUMPER_VARIABLES_CNT,
VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP,
VCD_SIGNAL_DUMPER_VARIABLE_ITTI_SEND_MSG,
diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
index c7f2ee7b5e..2f73d6978c 100644
--- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
+++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.c
@@ -38,6 +38,11 @@
#include
#include "bladerf_lib.h"
+/** @addtogroup _BLADERF_PHY_RF_INTERFACE_
+ * @{
+ */
+
+//! Number of BladeRF devices
#ifdef __SSE4_1__
# include
#endif
@@ -47,13 +52,21 @@
#endif
int num_devices=0;
+
/*These items configure the underlying asynch stream used by the the sync interface.
*/
-int trx_brf_init(openair0_device *openair0) {
+/*! \brief BladeRF Init function (not used at the moment)
+ * \param device RF frontend parameters set by application
+ */
+int trx_brf_init(openair0_device *device) {
}
+/*! \brief get current timestamp
+ *\param device the hardware to use
+ *\param module the bladeRf module
+ */
openair0_timestamp trx_get_timestamp(openair0_device *device, bladerf_module module) {
int status;
@@ -69,18 +82,31 @@ openair0_timestamp trx_get_timestamp(openair0_device *device, bladerf_module mod
return meta.timestamp;
}
-
-int trx_brf_start(openair0_device *openair0) {
+/*! \brief Start BladeRF
+ *\param device the hardware to use
+ */
+int trx_brf_start(openair0_device *device) {
return 0;
}
+/*! \brief Get BladeRF stats
+ *\param device the hardware to use
+ */
static void trx_brf_stats(openair0_device *device){
}
-static int trx_brf_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc) {
+/*! \brief Called to send samples to the BladeRF RF target
+ @param device pointer to the device structure specific to the RF hardware target
+ @param timestamp The timestamp at whicch the first sample MUST be sent
+ @param buff Buffer which holds the samples
+ @param nsamps number of samples to be sent
+ @param cc index of the component carrier
+ @param flags Ignored for the moment
+*/
+static int trx_brf_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc, int flags) {
int status;
brf_state_t *brf = (brf_state_t*)device->priv;
@@ -121,6 +147,16 @@ static int trx_brf_write(openair0_device *device,openair0_timestamp ptimestamp,
return(0);
}
+/*! \brief Receive samples from hardware.
+ * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
+ * the first channel. *ptimestamp is the time at which the first sample
+ * was received.
+ * \param device the hardware to use
+ * \param[out] ptimestamp the time at which the first sample was received.
+ * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
+ * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
+ * \param cc Index of component carrier
+*/
static int trx_brf_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
int status=0;
@@ -157,6 +193,9 @@ static int trx_brf_read(openair0_device *device, openair0_timestamp *ptimestamp,
}
+/*! \brief Terminate operation of the BladeRF transceiver -- free all associated resources
+ * \param device the hardware to use
+ */
int trx_brf_end(openair0_device *device) {
int status;
@@ -172,25 +211,39 @@ int trx_brf_end(openair0_device *device) {
return 0;
}
-
+/*! \brief print the BladeRF statistics
+* \param device the hardware to use
+* \returns 0 on success
+*/
int trx_brf_get_stats(openair0_device* device) {
return(0);
}
+/*! \brief Reset the BladeRF statistics
+* \param device the hardware to use
+* \returns 0 on success
+*/
int trx_brf_reset_stats(openair0_device* device) {
return(0);
}
+/*! \brief Stop USRP
+ * \param device the hardware to use
+ */
int trx_brf_stop(openair0_device* device) {
return(0);
}
+/*! \brief Set frequencies (TX/RX)
+ * \param device the hardware to use
+ * \returns 0 in success
+ */
int trx_brf_set_freq(openair0_device* device) {
int status;
@@ -213,12 +266,19 @@ int trx_brf_set_freq(openair0_device* device) {
return(0);
}
+
+/*! \brief Set Gains (TX/RX)
+ * \param device the hardware to use
+ * \returns 0 in success
+ */
int trx_brf_set_gains(openair0_device* device) {
return(0);
}
+
+
#define RXDCLENGTH 16384
int16_t cos_fsover8[8] = {2047, 1447, 0, -1448, -2047, -1448, 0, 1447};
int16_t cos_3fsover8[8] = {2047, -1448, 0, 1447, -2047, 1447, 0, -1448};
@@ -822,15 +882,23 @@ void calibrate_rf(openair0_device *device) {
// write_output("blade_rf_test.m","rxs",calib_buff,RXDCLENGTH,1,1);
}
-int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg) {
-
+/*! \brief Initialize Openair BLADERF target. It returns 0 if OK
+ * \param device the hardware to use
+ * \param openair0_cfg RF frontend parameters set by application
+ */
+int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
int status;
int card=0;
brf_state_t *brf = (brf_state_t*)malloc(sizeof(brf_state_t));
memset(brf, 0, sizeof(brf_state_t));
+ /* device specific */
+ openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered
+ openair0_cfg->txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
+ openair0_cfg->iq_txshift = 0;// shift
+ openair0_cfg->iq_rxrescale = 15;//rescale iqs
+
// init required params
-
switch ((int)openair0_cfg->sample_rate) {
case 30720000:
openair0_cfg->samples_per_packet = 2048;
@@ -857,7 +925,8 @@ int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openai
exit(-1);
break;
}
-
+ openair0_cfg->iq_txshift= 0;
+ openair0_cfg->iq_rxrescale = 15; /*not sure*/
openair0_cfg->rx_gain_calib_table = calib_table_fx4;
// The number of buffers to use in the underlying data stream
@@ -1001,6 +1070,7 @@ int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openai
printf("BLADERF: Initializing openair0_device\n");
device->priv = brf;
device->Mod_id = num_devices++;
+ device->type = BLADERF_DEV;
device->trx_start_func = trx_brf_start;
device->trx_end_func = trx_brf_end;
device->trx_read_func = trx_brf_read;
@@ -1019,6 +1089,9 @@ int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openai
return 0;
}
+/*! \brief bladeRF error report
+ * \param status
+ */
int brf_error(int status) {
//exit(-1);
@@ -1026,7 +1099,9 @@ int brf_error(int status) {
}
-
+/*! \brief Open BladeRF from serial port
+ * \param serial name of serial port on which to open BladeRF device
+ */
struct bladerf * open_bladerf_from_serial(const char *serial) {
int status;
@@ -1053,6 +1128,10 @@ struct bladerf * open_bladerf_from_serial(const char *serial) {
return dev;
}
}
+
+/*! \brief Get BladeRF log level
+ * \param log_level log level
+ */
int get_brf_log_level(int log_level){
int level=BLADERF_LOG_LEVEL_INFO;
@@ -1081,3 +1160,4 @@ int get_brf_log_level(int log_level){
}
return level;
}
+/*@}*/
diff --git a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h
index 15e1d39da7..3a05c80e5c 100644
--- a/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h
+++ b/targets/ARCH/BLADERF/USERSPACE/LIB/bladerf_lib.h
@@ -37,45 +37,69 @@
#include "common_lib.h"
#include "log.h"
+/** @addtogroup _BLADERF_PHY_RF_INTERFACE_
+ * @{
+ */
+
+/*! \brief BladeRF specific data structure */
typedef struct {
- // opaque BRF data struct
+ //! opaque BladeRF device struct. An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
struct bladerf *dev;
- // An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
-
+
+ //! Number of buffers
unsigned int num_buffers;
+ //! Buffer size
unsigned int buffer_size;
+ //! Number of transfers
unsigned int num_transfers;
+ //! RX timeout
unsigned int rx_timeout_ms;
+ //! TX timeout
unsigned int tx_timeout_ms;
-
+ //! Metadata for RX
struct bladerf_metadata meta_rx;
+ //!Metadata for TX
struct bladerf_metadata meta_tx;
-
+ //! Sample rate
unsigned int sample_rate;
- // time offset between transmiter timestamp and receiver timestamp;
+ //! time offset between transmiter timestamp and receiver timestamp;
double tdiff;
- // use brf_time_offset to get this value
+ //! TX number of forward samples use brf_time_offset to get this value
int tx_forward_nsamps; //166 for 20Mhz
// --------------------------------
// Debug and output control
// --------------------------------
+ //! Number of underflows
int num_underflows;
+ //! Number of overflows
int num_overflows;
+ //! number of sequential errors
int num_seq_errors;
+ //! number of RX errors
int num_rx_errors;
+ //! Number of TX errors
int num_tx_errors;
+ //! timestamp of current TX
uint64_t tx_current_ts;
+ //! timestamp of current RX
uint64_t rx_current_ts;
+ //! number of actual samples transmitted
uint64_t tx_actual_nsamps;
+ //! number of actual samples received
uint64_t rx_actual_nsamps;
+ //! number of TX samples
uint64_t tx_nsamps;
+ //! number of RX samples
uint64_t rx_nsamps;
+ //! number of TX count
uint64_t tx_count;
+ //! number of RX count
uint64_t rx_count;
+ //! timestamp of RX packet
openair0_timestamp rx_timestamp;
} brf_state_t;
@@ -84,3 +108,4 @@ typedef struct {
*/
int brf_error(int status);
+/*@}*/
diff --git a/targets/ARCH/COMMON/common_lib.c b/targets/ARCH/COMMON/common_lib.c
index 7479a6aa0b..e4ee06d0a4 100644
--- a/targets/ARCH/COMMON/common_lib.c
+++ b/targets/ARCH/COMMON/common_lib.c
@@ -37,31 +37,140 @@
* \warning
*/
#include
+#include
+#include
+#include
+#include
+
#include "common_lib.h"
+int set_device(openair0_device *device) {
-int openair0_device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
-
-#ifdef ETHERNET
- device->type=ETH_IF;
- device->func_type = BBU_FUNC;
- printf(" openair0_dev_init_eth ...\n");
- return(openair0_dev_init_eth(device, openair0_cfg));
-
-#elif EXMIMO
- device->type=EXMIMO_IF;
- printf("openair0_dev_init_exmimo...\n");
- return(openair0_dev_init_exmimo(device, openair0_cfg));
-#elif OAI_USRP
- device->type=USRP_B200_IF;
- printf("openair0_dev_init_usrp ...\n");
- return(openair0_dev_init_usrp(device, openair0_cfg));
-
-#elif OAI_BLADERF
- device->type=BLADERF_IF;
- printf(" openair0_dev_init_bladerf ...\n");
- return(openair0_dev_init_bladerf(device, openair0_cfg));
-
-#endif
-
+ switch (device->type) {
+
+ case EXMIMO_DEV:
+ printf("[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+ case USRP_B200_DEV:
+ printf("[%s] has loaded USRP B200 device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+case USRP_X300_DEV:
+ printf("[%s] has loaded USRP X300 device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+ case BLADERF_DEV:
+ printf("[%s] has loaded BLADERF device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+ case LMSSDR_DEV:
+ printf("[%s] has loaded LMSSDR device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+ case NONE_DEV:
+ printf("[%s] has not loaded a HW device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ break;
+ default:
+ printf("[%s] invalid HW device.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ return -1;
+ }
+ return 0;
}
+
+int set_transport(openair0_device *device) {
+
+ switch (device->transp_type) {
+
+ case ETHERNET_TP:
+ printf("[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ return 0;
+ break;
+ case NONE_TP:
+ printf("[%s] has not loaded a transport protocol.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ return 0;
+ break;
+ default:
+ printf("[%s] invalid transport protocol.\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"));
+ return -1;
+ break;
+ }
+
+}
+
+/* look for the interface library and load it */
+int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * cfg, uint8_t flag) {
+
+ void *lib_handle;
+ oai_device_initfunc_t dp ;
+ oai_transport_initfunc_t tp ;
+
+ if (flag == BBU_LOCAL_RADIO_HEAD) {
+ lib_handle = dlopen(OAI_RF_LIBNAME, RTLD_LAZY);
+ if (!lib_handle) {
+ printf( "Unable to locate %s: HW device set to NONE_DEV.\n", OAI_RF_LIBNAME);
+ return 0;
+ }
+
+ dp = dlsym(lib_handle,"device_init");
+
+ if (dp != NULL ) {
+ dp(device,openair0_cfg);
+ } else {
+ fprintf(stderr, "%s %d:oai device intializing function not found %s\n", __FILE__, __LINE__, dlerror());
+ return -1;
+ }
+ } else {
+ lib_handle = dlopen(OAI_TP_LIBNAME, RTLD_LAZY);
+ if (!lib_handle) {
+ printf( "Unable to locate %s: transport protocol set to NONE_TP.\n", OAI_TP_LIBNAME);
+ return 0;
+ }
+
+ tp = dlsym(lib_handle,"transport_init");
+
+ if (tp != NULL ) {
+ tp(device,openair0_cfg,cfg);
+ } else {
+ fprintf(stderr, "%s %d:oai device intializing function not found %s\n", __FILE__, __LINE__, dlerror());
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+
+int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg) {
+
+ int rc;
+ //ToDo: EXMIMO harmonization is not complete. That is the reason for this ifdef
+ #ifdef EXMIMO
+ device_init(device, openair0_cfg);
+ #else
+ rc=load_lib(device, openair0_cfg, NULL,BBU_LOCAL_RADIO_HEAD );
+ if ( rc >= 0) {
+ if ( set_device(device) < 0) {
+ fprintf(stderr, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
+ return -1;
+ }
+ }
+ #endif
+ return 0;
+}
+
+int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params) {
+ int rc;
+ rc=load_lib(device, openair0_cfg, eth_params, BBU_REMOTE_RADIO_HEAD);
+ if ( rc >= 0) {
+ if ( set_transport(device) < 0) {
+ fprintf(stderr, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
+ return -1;
+ }
+ }
+ return 0;
+
+}
+
+
+
+
+
+
+
diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h
index a3fe9e9dbd..dc0b31af58 100644
--- a/targets/ARCH/COMMON/common_lib.h
+++ b/targets/ARCH/COMMON/common_lib.h
@@ -42,11 +42,20 @@
#include
#include
+/* name of shared library implementing the radio front end */
+#define OAI_RF_LIBNAME "liboai_device.so"
+/* name of shared library implementing the transport */
+#define OAI_TP_LIBNAME "liboai_transpro.so"
+
+/* flags for BBU to determine whether the attached radio head is local or remote */
+#define BBU_LOCAL_RADIO_HEAD 0
+#define BBU_REMOTE_RADIO_HEAD 1
+
typedef int64_t openair0_timestamp;
typedef volatile int64_t openair0_vtimestamp;
-/* structrue holds the parameters to configure USRP devices*/
+/*!\brief structrue holds the parameters to configure USRP devices*/
typedef struct openair0_device_t openair0_device;
@@ -65,10 +74,56 @@ typedef enum {
} duplex_mode_t;
-/** @addtogroup _PHY_RF_INTERFACE_
+
+/** @addtogroup _GENERIC_PHY_RF_INTERFACE_
* @{
*/
-
+/*!\brief RF device types
+ */
+typedef enum {
+ MIN_RF_DEV_TYPE = 0,
+ /*!\brief device is ExpressMIMO */
+ EXMIMO_DEV,
+ /*!\brief device is USRP B200/B210*/
+ USRP_B200_DEV,
+ /*!\brief device is USRP X300/X310*/
+ USRP_X300_DEV,
+ /*!\brief device is BLADE RF*/
+ BLADERF_DEV,
+ /*!\brief device is LMSSDR (SoDeRa)*/
+ LMSSDR_DEV,
+ /*!\brief device is NONE*/
+ NONE_DEV,
+ MAX_RF_DEV_TYPE
+
+} dev_type_t;
+
+/*!\brief transport protocol types
+ */
+typedef enum {
+ MIN_TRANSP_TYPE = 0,
+ /*!\brief transport protocol ETHERNET */
+ ETHERNET_TP,
+ /*!\brief no transport protocol*/
+ NONE_TP,
+ MAX_TRANSP_TYPE
+
+} transport_type_t;
+
+
+/*!\brief openair0 device host type */
+typedef enum {
+ MIN_HOST_TYPE = 0,
+ /*!\brief device functions within a BBU */
+ BBU_HOST,
+ /*!\brief device functions within a RRH */
+ RRH_HOST,
+ MAX_HOST_TYPE
+
+}host_type_t;
+
+
+/*! \brief RF Gain clibration */
typedef struct {
//! Frequency for which RX chain was calibrated
double freq;
@@ -76,10 +131,11 @@ typedef struct {
double offset;
} rx_gain_calib_table_t;
+/*! \brief RF frontend parameters set by application */
typedef struct {
//! Module ID for this configuration
int Mod_id;
- // device log level
+ //! device log level
int log_level;
//! duplexing mode
duplex_mode_t duplex_mode;
@@ -90,11 +146,15 @@ typedef struct {
//! the sample rate for both transmit and receive.
double sample_rate;
//! number of samples per RX/TX packet (USRP + Ethernet)
- int samples_per_packet;
+ unsigned int samples_per_packet;
//! delay in sending samples (write) due to hardware access, softmodem processing and fronthaul delay if exist
int tx_scheduling_advance;
//! offset in samples between TX and RX paths
int tx_sample_advance;
+ //! configurable tx thread lauch delay
+ int txlaunch_wait; /* 1 or 0 */
+ //! configurable tx thread lauch delay
+ int txlaunch_wait_slotcount;
//! number of RX channels (=RX antennas)
int rx_num_channels;
//! number of TX channels (=TX antennas)
@@ -125,77 +185,72 @@ typedef struct {
double tx_bw;
//! Auto calibration flag
int autocal[4];
- //! RRH IP addr for Ethernet interface
- char *remote_ip;
- //! RRH port number for Ethernet interface
- int remote_port;
- //! my IP addr for Ethernet interface (eNB/BBU, UE)
- char *my_ip;
- //! my port number for Ethernet interface (eNB/BBU, UE)
- int my_port;
-
+ //! rf devices work with x bits iqs when oai have its own iq format
+ //! the two following parameters are used to convert iqs
+ int iq_txshift;
+ int iq_rxrescale;
+ //! remote IP/MAC addr for Ethernet interface
+ char *remote_addr;
+ //! remote port number for Ethernet interface
+ unsigned int remote_port;
+ //! local IP/MAC addr for Ethernet interface (eNB/BBU, UE)
+ char *my_addr;
+ //! local port number for Ethernet interface (eNB/BBU, UE)
+ unsigned int my_port;
+ //! Configuration file for LMS7002M
+ char *configFilename;
} openair0_config_t;
+/*! \brief RF mapping */
typedef struct {
- /* card id */
+ //! card id
int card;
- /* rf chain id */
+ //! rf chain id
int chain;
} openair0_rf_map;
-
-/*!\brief interface types that apply to modules (RRH_BBU/RRH_UE) created in RRH (rrh_gw.c)
- and are defined with respect to the RF device that is present in RRH
- -RRH_BBU modules have two devices, one is by default ETHERNET (will have ETH_IF) and the other one is a
- RF device (EXMIMO,USRP,BLADERF) or no device (NONE_IF).
- -RRH_UE modules have two devices one is by default ETHERNET (will have ETH_IF)
- and the other one by default not present so it will have NONE_IF
- */
-typedef enum {
- MIN_DEV_TYPE = 0,
- /*!\brief device is ETH */
- ETH_IF,
- /*!\brief device is ExpressMIMO */
- EXMIMO_IF,
- /*!\brief device is USRP B200/B210*/
- USRP_B200_IF,
- /*!\brief device is USRP X300/X310*/
- USRP_X300_IF,
- /*!\brief device is BLADE RF*/
- BLADERF_IF,
- /*!\brief device is NONE*/
- NONE_IF,
- MAX_DEV_TYPE
-
-} dev_type_t;
+typedef struct {
+ char *remote_addr;
+ //! remote port number for Ethernet interface
+ uint16_t remote_port;
+ //! local IP/MAC addr for Ethernet interface (eNB/BBU, UE)
+ char *my_addr;
+ //! local port number for Ethernet interface (eNB/BBU, UE)
+ uint16_t my_port;
+ //! local Ethernet interface (eNB/BBU, UE)
+ char *local_if_name;
+ //! tx_sample_advance for RF + ETH
+ uint8_t tx_sample_advance;
+ //! tx_scheduling_advance for RF + ETH
+ uint8_t tx_scheduling_advance;
+ //! iq_txshift for RF + ETH
+ uint8_t iq_txshift;
+ //! transport type preference (RAW/UDP)
+ uint8_t transp_preference;
+ //! radio front end preference (EXMIMO,USRP, BALDERF,LMSSDR)
+ uint8_t rf_preference;
+} eth_params_t;
-/*!\brief openair0 device host type */
-typedef enum {
- MIN_FUNC_TYPE = 0,
- /*!\brief device functions within a BBU */
- BBU_FUNC,
- /*!\brief device functions within a RRH */
- RRH_FUNC,
- MAX_FUNC_TYPE
-
-}func_type_t;
-
+/*!\brief structure holds the parameters to configure USRP devices */
struct openair0_device_t {
- /* Module ID of this device */
+ /*!brief Module ID of this device */
int Mod_id;
- /* Type of this device */
+ /*!brief Type of this device */
dev_type_t type;
- /* Type of the device's host (BBU/RRH) */
- func_type_t func_type;
+ /*!brief Transport protocol type that the device suppports (in case I/Q samples need to be transported) */
+ transport_type_t transp_type;
- /* RF frontend parameters set by application */
+ /*!brief Type of the device's host (BBU/RRH) */
+ host_type_t host_type;
+
+ /* !brief RF frontend parameters set by application */
openair0_config_t *openair0_cfg;
- /* Can be used by driver to hold internal structure*/
+ /*!brief Can be used by driver to hold internal structure*/
void *priv;
/* Functions API, which are called by the application*/
@@ -217,7 +272,7 @@ struct openair0_device_t {
@param msg pointer to the message structure passed between BBU-RRH
@param msg_len length of the message
*/
- int (*trx_reply_func)(openair0_device *openair0, void *msg, ssize_t msg_len);
+ int (*trx_reply_func)(openair0_device *device, void *msg, ssize_t msg_len);
/*! \brief Called to send samples to the RF target
@param device pointer to the device structure specific to the RF hardware target
@@ -235,9 +290,9 @@ struct openair0_device_t {
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
- * \param[out] An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
+ * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
- * \param cc Number of channels. If cc == 1, only buff[0] is filled with samples.
+ * \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read
*/
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
@@ -254,49 +309,64 @@ struct openair0_device_t {
*/
int (*trx_reset_stats_func)(openair0_device *device);
- /*! \brief Terminate operation of the transceiver -- free all associated resources */
+ /*! \brief Terminate operation of the transceiver -- free all associated resources
+ * \param device the hardware to use
+ */
void (*trx_end_func)(openair0_device *device);
- /* Terminate operation */
+ /*! \brief Stop operation of the transceiver
+ * \param card RF Card to use
+ */
int (*trx_stop_func)(int card);
/* Functions API related to UE*/
/*! \brief Set RX feaquencies
- * \param
+ * \param device the hardware to use
+ * \param openair0_cfg RF frontend parameters set by application
+ * \param exmimo_dump_config dump EXMIMO configuration
* \returns 0 in success
*/
int (*trx_set_freq_func)(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
/*! \brief Set gains
- * \param
+ * \param device the hardware to use
+ * \param openair0_cfg RF frontend parameters set by application
* \returns 0 in success
*/
int (*trx_set_gains_func)(openair0_device* device, openair0_config_t *openair0_cfg);
};
+/* type of device init function, implemented in shared lib */
+typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg);
+/* type of transport init function, implemented in shared lib */
+typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params);
#ifdef __cplusplus
extern "C"
{
#endif
-/*! \brief Initialize Openair RF target. It returns 0 if OK */
- int openair0_device_init(openair0_device* device, openair0_config_t *openair0_cfg);
+
+ /*! \brief Initialize openair RF target. It returns 0 if OK */
+ int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
+ /*! \brief Initialize transport protocol . It returns 0 if OK */
+ int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params);
+
- //USRP
-/*! \brief Get the current timestamp of USRP */
+ /*! \brief Get current timestamp of USRP
+ * \param device the hardware to use
+ */
openair0_timestamp get_usrp_time(openair0_device *device);
-/*! \brief Set the RX frequency of USRP RF TARGET */
+
+ /*! \brief Set RX frequencies
+ * \param device the hardware to use
+ * \param openair0_cfg RF frontend parameters set by application
+ * \returns 0 in success
+ */
int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
-
-//extern
-/*! \brief Initialize Openair ETHERNET target. It returns 0 if OK */
- int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg);
- int openair0_dev_init_bladerf(openair0_device *device, openair0_config_t *openair0_cfg);
- int openair0_dev_init_usrp(openair0_device* device, openair0_config_t *openair0_cfg);
- int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg);
+
/*@}*/
#ifdef __cplusplus
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
new file mode 100644
index 0000000000..a360f26556
--- /dev/null
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_raw.c
@@ -0,0 +1,319 @@
+/*******************************************************************************
+ OpenAirInterface
+ Copyright(c) 1999 - 2014 Eurecom
+
+ OpenAirInterface is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+
+ OpenAirInterface is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenAirInterface.The full GNU General Public License is
+ included in this distribution in the file called "COPYING". If not,
+ see .
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
+
+ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+/*! \file ethernet_lib.c
+ * \brief API to stream I/Q samples over standard ethernet
+ * \author add alcatel Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
+ * \date 2015
+ * \version 0.2
+ * \company Eurecom
+ * \maintainer: navid.nikaein@eurecom.fr
+ * \note
+ * \warning
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "common_lib.h"
+#include "ethernet_lib.h"
+
+#define DEBUG 0
+
+struct sockaddr_ll dest_addr[MAX_INST];
+struct sockaddr_ll local_addr[MAX_INST];
+int addr_len[MAX_INST];
+struct ifreq if_index[MAX_INST];
+struct ether_header eh;
+
+int eth_socket_init_raw(openair0_device *device) {
+
+ int i = 0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ const char *local_mac, *remote_mac;
+ int local_port=0, remote_port=0;
+ int sock_dom=0;
+ int sock_type=0;
+ int sock_proto=0;
+
+ if (device->host_type == RRH_HOST ) { /* RRH doesn't know remote MAC(will be retrieved from first packet send from BBU) and remote port(don't care) */
+ local_mac = device->openair0_cfg->my_addr;
+ local_port = device->openair0_cfg->my_port;
+ remote_mac = malloc(ETH_ALEN);
+ memset(remote_mac,0,ETH_ALEN);
+ remote_port = 0;
+ printf("[%s] local MAC addr %s remote MAC addr %s\n","RRH", local_mac,remote_mac);
+ } else {
+ local_mac = device->openair0_cfg->my_addr;
+ local_port = device->openair0_cfg->my_port;
+ remote_mac = device->openair0_cfg->remote_addr;
+ remote_port = device->openair0_cfg->remote_port;
+ printf("[%s] local MAC addr %s remote MAC addr %s\n","BBU", local_mac,remote_mac);
+ }
+
+
+ /* Open a RAW socket to send on */
+ sock_dom=AF_PACKET;
+ sock_type=SOCK_RAW;
+ sock_proto=IPPROTO_RAW;
+ if ((eth->sockfd[Mod_id] = socket(sock_dom, sock_type, sock_proto)) == -1) {
+ perror("ETHERNET: Error opening RAW socket");
+ exit(0);
+ }
+
+ /* initialize destination address */
+ for (i=0; i< MAX_INST; i++) {
+ bzero((void *)&(local_addr[i]), sizeof(struct sockaddr_ll));
+ bzero((void *)&(if_index[i]), sizeof(struct ifreq));
+ }
+ /* Get the index of the interface to send on */
+ strcpy(if_index[Mod_id].ifr_name,eth->if_name[Mod_id]);
+ if (ioctl(eth->sockfd[Mod_id], SIOCGIFINDEX, &(if_index[Mod_id])) < 0)
+ perror("SIOCGIFINDEX");
+
+ local_addr[Mod_id].sll_family = AF_PACKET;
+ local_addr[Mod_id].sll_ifindex = if_index[Mod_id].ifr_ifindex;
+ /* hear traffic from specific protocol*/
+ local_addr[Mod_id].sll_protocol = htons((short)device->openair0_cfg->my_port);
+ local_addr[Mod_id].sll_halen = ETH_ALEN;
+ local_addr[Mod_id].sll_pkttype = PACKET_OTHERHOST;
+ addr_len[Mod_id] = sizeof(struct sockaddr_ll);
+
+ if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&local_addr[Mod_id],addr_len[Mod_id])<0) {
+ perror("ETHERNET: Cannot bind to socket");
+ exit(0);
+ }
+
+ /* Construct the Ethernet header */
+ ether_aton_r(local_mac, (struct ether_addr *)(&(eh.ether_shost)));
+ ether_aton_r(remote_mac, (struct ether_addr *)(&(eh.ether_dhost)));
+ eh.ether_type = htons((short)device->openair0_cfg->my_port);
+
+ printf("[%s] binding mod_%d to hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"),Mod_id,eh.ether_shost[0],eh.ether_shost[1],eh.ether_shost[2],eh.ether_shost[3],eh.ether_shost[4],eh.ether_shost[5]);
+
+ return 0;
+}
+
+
+int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
+
+ int bytes_sent=0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ int sendto_flag =0;
+ int i=0;
+ //sendto_flag|=flags;
+
+ eth->tx_nsamps=nsamps;
+
+ for (i=0;isockfd[Mod_id],RAW_PACKET_SIZE_BYTES(nsamps), buff2);*/
+
+ while(bytes_sent < RAW_PACKET_SIZE_BYTES(nsamps)) {
+#if DEBUG
+ printf("------- TX ------: buff2 current position=%d remaining_bytes=%d bytes_sent=%d \n",
+ (void *)(buff2+bytes_sent),
+ RAW_PACKET_SIZE_BYTES(nsamps) - bytes_sent,
+ bytes_sent);
+#endif
+ /* Send packet */
+ bytes_sent += send(eth->sockfd[Mod_id],
+ buff2,
+ RAW_PACKET_SIZE_BYTES(nsamps),
+ sendto_flag);
+ if ( bytes_sent == -1) {
+ eth->num_tx_errors++;
+ perror("ETHERNET WRITE: ");
+ exit(-1);
+ } else {
+#if DEBUG
+ printf("------- TX ------: nu=%x an_id=%d ts%d bytes_sent=%d\n",
+ *(uint8_t *)(buff2+ETH_ALEN),
+ *(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t)),
+ *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)),
+ bytes_sent);
+ dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, RAW_PACKET_SIZE_BYTES(nsamps), TX_FLAG);
+#endif
+ eth->tx_actual_nsamps=bytes_sent>>2;
+ eth->tx_count++;
+ }
+ }
+
+ /* tx buffer values restored */
+ *(struct ether_header *)buff2 = temp;
+ *(int32_t *)(buff2 + MAC_HEADER_SIZE_BYTES) = temp0;
+ *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = temp1;
+ }
+ return (bytes_sent-APP_HEADER_SIZE_BYTES-MAC_HEADER_SIZE_BYTES)>>2;
+}
+
+
+int trx_eth_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+
+ int bytes_received=0;
+ int i=0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ int rcvfrom_flag =0;
+
+ eth->rx_nsamps=nsamps;
+
+ for (i=0;isockfd[Mod_id],
+ buff2,
+ RAW_PACKET_SIZE_BYTES(nsamps),
+ rcvfrom_flag);
+
+ if (bytes_received ==-1) {
+ eth->num_rx_errors++;
+ perror("ETHERNET READ: ");
+ exit(-1);
+ } else {
+ /* store the timestamp value from packet's header */
+ *timestamp = *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t));
+ eth->rx_actual_nsamps=bytes_received>>2;
+ eth->rx_count++;
+ }
+ }
+
+#if DEBUG
+ printf("------- RX------: nu=%x an_id=%d ts%d bytes_recv=%d \n",
+ *(uint8_t *)(buff2+ETH_ALEN),
+ *(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t)),
+ *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)),
+ bytes_received);
+ dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, RAW_PACKET_SIZE_BYTES(nsamps),RX_FLAG);
+
+#endif
+
+ /* tx buffer values restored */
+ *(struct ether_header *)buff2 = temp;
+ *(int32_t *)(buff2 + MAC_HEADER_SIZE_BYTES) = temp0;
+ *(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = temp1;
+ }
+ return (bytes_received-APP_HEADER_SIZE_BYTES-MAC_HEADER_SIZE_BYTES)>>2;
+}
+
+
+
+
+int eth_set_dev_conf_raw(openair0_device *device) {
+
+ int Mod_id = device->Mod_id;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ void *msg;
+ ssize_t msg_len;
+
+ /* a BBU client sends to RRH a set of configuration parameters (openair0_config_t)
+ so that RF front end is configured appropriately and
+ frame/packet size etc. can be set */
+
+ msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
+ msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
+
+
+ memcpy(msg,(void*)&eh,MAC_HEADER_SIZE_BYTES);
+ memcpy((msg+MAC_HEADER_SIZE_BYTES),(void*)device->openair0_cfg,sizeof(openair0_config_t));
+
+ if (send(eth->sockfd[Mod_id],
+ msg,
+ msg_len,
+ 0)==-1) {
+ perror("ETHERNET: ");
+ exit(0);
+ }
+
+ return 0;
+}
+
+
+int eth_get_dev_conf_raw(openair0_device *device) {
+
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ char str[INET_ADDRSTRLEN];
+ void *msg;
+ ssize_t msg_len;
+
+ msg = malloc(MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t));
+ msg_len = MAC_HEADER_SIZE_BYTES + sizeof(openair0_config_t);
+
+ /* RRH receives from BBU openair0_config_t */
+ if (recv(eth->sockfd[Mod_id],
+ msg,
+ msg_len,
+ 0)==-1) {
+ perror("ETHERNET: ");
+ exit(0);
+ }
+
+ /* RRH stores the remote MAC address */
+ memcpy(eh.ether_dhost,(msg+ETH_ALEN),ETH_ALEN);
+ //memcpy((void*)&device->openair0_cfg,(msg + MAC_HEADER_SIZE_BYTES), sizeof(openair0_config_t));
+ device->openair0_cfg=(openair0_config_t *)(msg + MAC_HEADER_SIZE_BYTES);
+ printf("[%s] binding mod_%d to hardware address %x:%x:%x:%x:%x:%x hardware address %x:%x:%x:%x:%x:%x\n",((device->host_type == BBU_HOST) ? "BBU": "RRH"),Mod_id,eh.ether_shost[0],eh.ether_shost[1],eh.ether_shost[2],eh.ether_shost[3],eh.ether_shost[4],eh.ether_shost[5],eh.ether_dhost[0],eh.ether_dhost[1],eh.ether_dhost[2],eh.ether_dhost[3],eh.ether_dhost[4],eh.ether_dhost[5]);
+
+ return 0;
+}
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
new file mode 100644
index 0000000000..a9706c73bd
--- /dev/null
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c
@@ -0,0 +1,383 @@
+/*******************************************************************************
+ OpenAirInterface
+ Copyright(c) 1999 - 2014 Eurecom
+
+ OpenAirInterface is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+
+ OpenAirInterface is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenAirInterface.The full GNU General Public License is
+ included in this distribution in the file called "COPYING". If not,
+ see .
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
+
+ Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
+
+ *******************************************************************************/
+/*! \file ethernet_lib.c
+ * \brief API to stream I/Q samples over standard ethernet
+ * \author add alcatel Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
+ * \date 2015
+ * \version 0.2
+ * \company Eurecom
+ * \maintainer: navid.nikaein@eurecom.fr
+ * \note
+ * \warning
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "vcd_signal_dumper.h"
+
+#include "common_lib.h"
+#include "ethernet_lib.h"
+
+#define DEBUG 0
+struct sockaddr_in dest_addr[MAX_INST];
+struct sockaddr_in local_addr[MAX_INST];
+int addr_len[MAX_INST];
+
+
+uint16_t pck_seq_num = 1;
+uint16_t pck_seq_num_cur=0;
+uint16_t pck_seq_num_prev=0;
+
+ int eth_socket_init_udp(openair0_device *device) {
+
+ int i = 0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ char str_local[INET_ADDRSTRLEN];
+ char str_remote[INET_ADDRSTRLEN];
+ const char *local_ip, *remote_ip;
+ int local_port=0, remote_port=0;
+ int sock_dom=0;
+ int sock_type=0;
+ int sock_proto=0;
+ int enable=1;
+
+ if (device->host_type == RRH_HOST ) {
+ local_ip = device->openair0_cfg->my_addr;
+ local_port = device->openair0_cfg->my_port;
+ remote_ip = "0.0.0.0";
+ remote_port = 0;
+ printf("[%s] local ip addr %s port %d\n", "RRH", local_ip, local_port);
+ } else {
+ local_ip = device->openair0_cfg->my_addr;
+ local_port = device->openair0_cfg->my_port;
+ remote_ip = device->openair0_cfg->remote_addr;
+ remote_port = device->openair0_cfg->remote_port;
+ printf("[%s] local ip addr %s port %d\n","BBU", local_ip, local_port);
+ }
+
+ /* Open socket to send on */
+ sock_dom=AF_INET;
+ sock_type=SOCK_DGRAM;
+ sock_proto=IPPROTO_UDP;
+
+ if ((eth->sockfd[Mod_id] = socket(sock_dom, sock_type, sock_proto)) == -1) {
+ perror("ETHERNET: Error opening socket");
+ exit(0);
+ }
+
+ /* initialize addresses */
+ for (i=0; i< MAX_INST; i++) {
+ bzero((void *)&(dest_addr[i]), sizeof(dest_addr[i]));
+ bzero((void *)&(local_addr[i]), sizeof(local_addr[i]));
+ }
+
+ addr_len[Mod_id] = sizeof(struct sockaddr_in);
+
+ dest_addr[Mod_id].sin_family = AF_INET;
+ inet_pton(AF_INET,remote_ip,&(dest_addr[Mod_id].sin_addr.s_addr));
+ dest_addr[Mod_id].sin_port=htons(remote_port);
+ inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str_remote, INET_ADDRSTRLEN);
+
+
+ local_addr[Mod_id].sin_family = AF_INET;
+ inet_pton(AF_INET,local_ip,&(local_addr[Mod_id].sin_addr.s_addr));
+ local_addr[Mod_id].sin_port=htons(local_port);
+ inet_ntop(AF_INET, &(local_addr[Mod_id].sin_addr), str_local, INET_ADDRSTRLEN);
+
+
+ /* set reuse address flag */
+ if (setsockopt(eth->sockfd[Mod_id], SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
+ perror("ETHERNET: Cannot set SO_REUSEADDR option on socket");
+ exit(0);
+ }
+
+ /* want to receive -> so bind */
+ if (bind(eth->sockfd[Mod_id],(struct sockaddr *)&local_addr[Mod_id],addr_len[Mod_id])<0) {
+ perror("ETHERNET: Cannot bind to socket");
+ exit(0);
+ } else {
+ printf("[%s] binding mod_%d to %s:%d\n","RRH",Mod_id,str_local,ntohs(local_addr[Mod_id].sin_port));
+ }
+
+ return 0;
+}
+
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
+
+ int bytes_sent=0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ int sendto_flag =0;
+ int i=0;
+ //sendto_flag|=flags;
+ eth->tx_nsamps=nsamps;
+
+ for (i=0;ipck_header.seq_num = pck_seq_num;
+ //eth->pck_header.antenna_id = 1+(i<<1);
+ //eth->pck_header.timestamp = timestamp;
+ *(uint16_t *)buff2 = pck_seq_num;
+ *(uint16_t *)(buff2 + sizeof(uint16_t)) = 1+(i<<1);
+ *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = timestamp;
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TX_SEQ_NUM, pck_seq_num);
+
+ while(bytes_sent < UDP_PACKET_SIZE_BYTES(nsamps)) {
+#if DEBUG
+ printf("------- TX ------: buff2 current position=%d remaining_bytes=%d bytes_sent=%d \n",
+ (void *)(buff2+bytes_sent),
+ UDP_PACKET_SIZE_BYTES(nsamps) - bytes_sent,
+ bytes_sent);
+#endif
+ /* Send packet */
+ bytes_sent += sendto(eth->sockfd[Mod_id],
+ buff2,
+ UDP_PACKET_SIZE_BYTES(nsamps),
+ sendto_flag,
+ (struct sockaddr*)&dest_addr[Mod_id],
+ addr_len[Mod_id]);
+
+ if ( bytes_sent == -1) {
+ eth->num_tx_errors++;
+ perror("ETHERNET WRITE: ");
+ exit(-1);
+ } else {
+#if DEBUG
+ printf("------- TX ------: nu=%d an_id=%d ts%d bytes_send=%d\n",
+ *(int16_t *)buff2,
+ *(int16_t *)(buff2 + sizeof(int16_t)),
+ *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
+ bytes_sent);
+ dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, UDP_PACKET_SIZE_BYTES(nsamps), TX_FLAG);
+#endif
+ eth->tx_actual_nsamps=bytes_sent>>2;
+ eth->tx_count++;
+ pck_seq_num++;
+ if ( pck_seq_num > MAX_PACKET_SEQ_NUM(nsamps,76800) ) pck_seq_num = 1;
+ }
+ }
+ /* tx buffer values restored */
+ *(int32_t *)buff2 = temp0;
+ *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
+ }
+
+ return (bytes_sent-APP_HEADER_SIZE_BYTES)>>2;
+}
+
+
+
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+
+ int bytes_received=0;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ openair0_timestamp prev_timestamp = -1;
+ int Mod_id = device->Mod_id;
+ int rcvfrom_flag =0;
+ int block_cnt=0;
+ int again_cnt=0;
+ int i=0;
+
+ eth->rx_nsamps=nsamps;
+
+ for (i=0;isockfd[Mod_id],
+ buff2,
+ UDP_PACKET_SIZE_BYTES(nsamps),
+ rcvfrom_flag,
+ (struct sockaddr *)&dest_addr[Mod_id],
+ (socklen_t *)&addr_len[Mod_id]);
+
+ if (bytes_received ==-1) {
+ eth->num_rx_errors++;
+ if (errno == EAGAIN) {
+ again_cnt++;
+ usleep(10);
+ if (again_cnt == 1000) {
+ perror("ETHERNET READ: ");
+ exit(-1);
+ } else {
+ printf("AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN AGAIN \n");
+ goto again;
+ }
+ } else if (errno == EWOULDBLOCK) {
+ block_cnt++;
+ usleep(10);
+ if (block_cnt == 1000) {
+ perror("ETHERNET READ: ");
+ exit(-1);
+ } else {
+ printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
+ goto again;
+ }
+ }
+ } else {
+#if DEBUG
+ printf("------- RX------: nu=%d an_id=%d ts%d bytes_recv=%d\n",
+ *(int16_t *)buff2,
+ *(int16_t *)(buff2 + sizeof(int16_t)),
+ *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
+ bytes_received);
+ dump_packet((device->host_type == BBU_HOST)? "BBU":"RRH", buff2, UDP_PACKET_SIZE_BYTES(nsamps),RX_FLAG);
+#endif
+
+ /* store the timestamp value from packet's header */
+ *timestamp = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
+ /* store the sequence number of the previous packet received */
+ if (pck_seq_num_cur == 0) {
+ pck_seq_num_prev = *(uint16_t *)buff2;
+ } else {
+ pck_seq_num_prev = pck_seq_num_cur;
+ }
+ /* get the packet sequence number from packet's header */
+ pck_seq_num_cur = *(uint16_t *)buff2;
+ //printf("cur=%d prev=%d buff=%d\n",pck_seq_num_cur,pck_seq_num_prev,*(uint16_t *)(buff2));
+ if ( ( pck_seq_num_cur != (pck_seq_num_prev + 1) ) && !((pck_seq_num_prev==75) && (pck_seq_num_cur==1 ))){
+ printf("out of order packet received1! %d|%d|%d\n",pck_seq_num_cur,pck_seq_num_prev, *timestamp);
+ }
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM,pck_seq_num_cur);
+ VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RX_SEQ_NUM_PRV,pck_seq_num_prev);
+ eth->rx_actual_nsamps=bytes_received>>2;
+ eth->rx_count++;
+ }
+
+ }
+ /* tx buffer values restored */
+ *(int32_t *)buff2 = temp0;
+ *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
+
+ }
+ return (bytes_received-APP_HEADER_SIZE_BYTES)>>2;
+}
+
+
+
+
+int eth_set_dev_conf_udp(openair0_device *device) {
+
+ int Mod_id = device->Mod_id;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ void *msg;
+ ssize_t msg_len;
+
+
+ /* a BBU client sents to RRH a set of configuration parameters (openair0_config_t)
+ so that RF front end is configured appropriately and
+ frame/packet size etc. can be set */
+
+ msg=malloc(sizeof(openair0_config_t));
+ msg_len=sizeof(openair0_config_t);
+ memcpy(msg,(void*)device->openair0_cfg,msg_len);
+
+ if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&dest_addr[Mod_id],addr_len[Mod_id])==-1) {
+ perror("ETHERNET: ");
+ exit(0);
+ }
+
+ return 0;
+}
+
+int eth_get_dev_conf_udp(openair0_device *device) {
+
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ int Mod_id = device->Mod_id;
+ char str1[INET_ADDRSTRLEN],str[INET_ADDRSTRLEN];
+ void *msg;
+ ssize_t msg_len;
+
+ msg=malloc(sizeof(openair0_config_t));
+ msg_len=sizeof(openair0_config_t);
+
+ inet_ntop(AF_INET, &(local_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str1, INET_ADDRSTRLEN);
+
+ /* RRH receives from BBU openair0_config_t */
+ if (recvfrom(eth->sockfd[Mod_id],
+ msg,
+ msg_len,
+ 0,
+ (struct sockaddr *)&dest_addr[Mod_id],
+ (socklen_t *)&addr_len[Mod_id])==-1) {
+ perror("ETHERNET: ");
+ exit(0);
+ }
+ device->openair0_cfg=(openair0_config_t *)msg;
+
+ /* get remote ip address and port */
+ /* inet_ntop(AF_INET, &(dest_addr[Mod_id].sin_addr), str1, INET_ADDRSTRLEN); */
+ /* device->openair0_cfg->remote_port =ntohs(dest_addr[Mod_id].sin_port); */
+ /* device->openair0_cfg->remote_addr =str1; */
+
+ /* /\* restore local ip address and port *\/ */
+ /* inet_ntop(AF_INET, &(local_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN); */
+ /* device->openair0_cfg->my_port =ntohs(local_addr[Mod_id].sin_port); */
+ /* device->openair0_cfg->my_addr =str; */
+
+ /* printf("[RRH] mod_%d socket %d connected to BBU %s:%d %s:%d\n", Mod_id, eth->sockfd[Mod_id],str1, device->openair0_cfg->remote_port, str, device->openair0_cfg->my_port); */
+ return 0;
+}
diff --git a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
index ce90d2cff9..f15f2d98eb 100644
--- a/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
+++ b/targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c
@@ -28,7 +28,7 @@
*******************************************************************************/
/*! \file ethernet_lib.c
* \brief API to stream I/Q samples over standard ethernet
- * \author Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
+ * \author add alcatel Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
* \date 2015
* \version 0.2
* \company Eurecom
@@ -52,196 +52,56 @@
#include "common_lib.h"
#include "ethernet_lib.h"
-//#define DEBUG 1
int num_devices_eth = 0;
+struct sockaddr_in dest_addr[MAX_INST];
int dest_addr_len[MAX_INST];
-char sendbuf[MAX_INST][BUF_SIZ]; /*TODO*/
-
-
-/*! \fn static int eth_socket_init(openair0_device *device)
-* \brief initialization of UDP Socket to communicate with one destination
-* \param[in] *device openair device for which the socket will be created
-* \param[out]
-* \return 0 on success, otherwise -1
-* \note
-* @ingroup _oai
-*/
-static int eth_socket_init(openair0_device *device);
-
-/*! \fn static int eth_set_dev_conf(openair0_device *device)
-* \brief
-* \param[in] *device openair device
-* \param[out]
-* \return 0 on success, otherwise -1
-* \note
-* @ingroup _oai
-*/
-static int eth_set_dev_conf(openair0_device *device);
-
-/*! \fn static int eth_get_dev_conf(openair0_device *device)
-* \brief
-* \param[in] *device openair device
-* \param[out]
-* \return 0 on success, otherwise -1
-* \note
-* @ingroup _oai
-*/
-static int eth_get_dev_conf(openair0_device *device);
-
int trx_eth_start(openair0_device *device) {
+
+ eth_state_t *eth = (eth_state_t*)device->priv;
/* initialize socket */
- if (eth_socket_init(device)!=0) {
- return -1;
- }
-
- /* RRH gets openair0 device configuration BBU sets openair0 device configuration*/
- if (device->func_type == BBU_FUNC) {
- return eth_set_dev_conf(device);
+ if ((eth->flags & ETH_RAW_MODE) != 0 ) {
+ if (eth_socket_init_raw(device)!=0) return -1;
+ /* RRH gets openair0 device configuration - BBU sets openair0 device configuration*/
+ if (device->host_type == BBU_HOST) {
+ if(eth_set_dev_conf_raw(device)!=0) return -1;
+ } else {
+ if(eth_get_dev_conf_raw(device)!=0) return -1;
+ }
+ /* adjust MTU wrt number of samples per packet */
+ if(ethernet_tune (device,MTU_SIZE,RAW_PACKET_SIZE_BYTES(device->openair0_cfg->samples_per_packet))!=0) return -1;
} else {
- return eth_get_dev_conf(device);
+ if (eth_socket_init_udp(device)!=0) return -1;
+ /* RRH gets openair0 device configuration - BBU sets openair0 device configuration*/
+ if (device->host_type == BBU_HOST) {
+ if(eth_set_dev_conf_udp(device)!=0) return -1;
+ } else {
+ if(eth_get_dev_conf_udp(device)!=0) return -1;
+ }
+ /* adjust MTU wrt number of samples per packet */
+ //if(ethernet_tune (device,MTU_SIZE,UDP_PACKET_SIZE_BYTES(device->openair0_cfg->samples_per_packet))!=0) return -1;
}
-
+ /* apply additional configuration */
+ if(ethernet_tune (device, SND_BUF_SIZE,2000000000)!=0) return -1;
+ if(ethernet_tune (device, RCV_BUF_SIZE,2000000000)!=0) return -1;
+
return 0;
}
-int trx_eth_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
-
- int n_written=0,i;
- uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
- eth_state_t *eth = (eth_state_t*)device->priv;
- int Mod_id = device->Mod_id;
- int sendto_flag =0;
- sendto_flag|=MSG_DONTWAIT;
-
- for (i=0;isockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
-
- while(n_written < nsamps) {
- /* Send packet */
- if ((n_written += sendto(eth->sockfd[Mod_id],
- buff2,
- (nsamps<<2)+header_size,
- 0,
- (struct sockaddr*)ð->dest_addr[Mod_id],
- dest_addr_len[Mod_id])) < 0) {
- perror("ETHERNET WRITE");
- exit(-1);
- }
- }
-
-#if DEBUG
- printf("Buffer head TX: nu=%d an_id=%d ts%d samples_send=%d i=%d data=%x\n",
- *(int16_t *)buff2,
- *(int16_t *)(buff2 + sizeof(int16_t)),
- *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
- n_written>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
-#endif
-
- /* tx buffer values restored */
- *(int32_t *)buff2 = temp0;
- *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
- }
- return n_written;
-
-}
-
-int trx_eth_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
-
- int bytes_received=0;
- int block_cnt=0;
- int ret=0,i;
- uint16_t header_size=sizeof(int32_t) + sizeof(openair0_timestamp);
-
- eth_state_t *eth = (eth_state_t*)device->priv;
- int Mod_id = device->Mod_id;
-
- for (i=0;isockfd[Mod_id],(nsamps<<2)+header_size, buff2, antenna_id);*/
-
- while(bytes_received < (int)((nsamps<<2))) {
- ret=recvfrom(eth->sockfd[Mod_id],
- buff2+bytes_received,
- (nsamps<<2)+header_size-bytes_received,
- 0,//MSG_DONTWAIT,
- (struct sockaddr *)ð->dest_addr[Mod_id],
- (socklen_t *)&dest_addr_len[Mod_id]);
-
- if (ret==-1) {
- if (errno == EAGAIN) {
- perror("ETHERNET READ: ");
- return((nsamps<<2) + header_size);
- } else if (errno == EWOULDBLOCK) {
- block_cnt++;
- usleep(10);
-
- if (block_cnt == 100) return(-1);
- }
- } else {
- bytes_received+=ret;
- }
- }
-
-#if DEBUG
- printf("Buffer head RX: nu=%d an_id=%d ts%d samples_recv=%d i=%d data=%x\n",
- *(int16_t *)buff2,
- *(int16_t *)(buff2 + sizeof(int16_t)),
- *(openair0_timestamp *)(buff2 + sizeof(int32_t)),
- ret>>2,i,*(int32_t *)(buff2 + 20*sizeof(int32_t)));
-#endif
-
- /* store the timestamp value from packet's header */
- *timestamp = *(openair0_timestamp *)(buff2 + sizeof(int32_t));
-
- /* tx buffer values restored */
- *(int32_t *)buff2 = temp0;
- *(openair0_timestamp *)(buff2 + sizeof(int32_t)) = temp1;
- }
- return nsamps;
-
-}
-
void trx_eth_end(openair0_device *device) {
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id = device->Mod_id;
- /*destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
+ /* destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
if ( close(eth->sockfd[Mod_id]) <0 ) {
perror("ETHERNET: Failed to close socket");
exit(0);
} else {
- printf("[RRH] socket for mod_id %d has been successfully closed.\n",Mod_id);
+ printf("[%s] socket for mod_id %d has been successfully closed.\n",(device->host_type == BBU_HOST)? "BBU":"RRH",Mod_id);
}
}
@@ -253,7 +113,7 @@ int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
eth_state_t *eth = (eth_state_t*)device->priv;
/* BBU sends a message to RRH */
- if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)ð->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
+ if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)&dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
perror("ETHERNET: ");
exit(0);
}
@@ -262,7 +122,6 @@ int trx_eth_request(openair0_device *device, void *msg, ssize_t msg_len) {
}
-
int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
eth_state_t *eth = (eth_state_t*)device->priv;
@@ -273,7 +132,7 @@ int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
msg,
msg_len,
0,
- (struct sockaddr *)ð->dest_addr[Mod_id],
+ (struct sockaddr *)&dest_addr[Mod_id],
(socklen_t *)&dest_addr_len[Mod_id])==-1) {
perror("ETHERNET: ");
exit(0);
@@ -283,65 +142,6 @@ int trx_eth_reply(openair0_device *device, void *msg, ssize_t msg_len) {
}
-static int eth_set_dev_conf(openair0_device *device) {
-
- int Mod_id = device->Mod_id;
- eth_state_t *eth = (eth_state_t*)device->priv;
- void *msg;
- ssize_t msg_len;
-
-
- /* a BBU client sents to RRH a set of configuration parameters (openair0_config_t)
- so that RF front end is configured appropriately and
- frame/packet size etc. can be set */
-
- msg=malloc(sizeof(openair0_config_t));
- msg_len=sizeof(openair0_config_t);
- memcpy(msg,(void*)&device->openair0_cfg,msg_len);
-
- if (sendto(eth->sockfd[Mod_id],msg,msg_len,0,(struct sockaddr *)ð->dest_addr[Mod_id],dest_addr_len[Mod_id])==-1) {
- perror("ETHERNET: ");
- exit(0);
- }
-
- return 0;
-}
-
-
-static int eth_get_dev_conf(openair0_device *device) {
-
- eth_state_t *eth = (eth_state_t*)device->priv;
- int Mod_id = device->Mod_id;
- char str[INET_ADDRSTRLEN];
- void *msg;
- ssize_t msg_len;
-
- msg=malloc(sizeof(openair0_config_t));
- msg_len=sizeof(openair0_config_t);
-
- /* RRH receives from BBU openair0_config_t */
- if (recvfrom(eth->sockfd[Mod_id],
- msg,
- msg_len,
- 0,
- (struct sockaddr *)ð->dest_addr[Mod_id],
- (socklen_t *)&dest_addr_len[Mod_id])==-1) {
- perror("ETHERNET: ");
- exit(0);
- }
-
- memcpy((void*)&device->openair0_cfg,msg,msg_len);
- inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
- device->openair0_cfg.remote_port =ntohs(eth->dest_addr[Mod_id].sin_port);
- device->openair0_cfg.remote_ip=str;
- /*apply additional configuration*/
- //ethernet_tune (device, RING_PAR);
- // printf("[RRH] write mod_%d %d to %s:%d\n",Mod_id,eth->sockfd[Mod_id],str,ntohs(eth->dest_addr[Mod_id].sin_port));
-
- return 0;
-}
-
-
int trx_eth_stop(int card) {
return(0);
@@ -364,186 +164,307 @@ int trx_eth_reset_stats(openair0_device* device) {
}
-static int eth_socket_init(openair0_device *device) {
-
- int i = 0;
- eth_state_t *eth = (eth_state_t*)device->priv;
- int Mod_id = device->Mod_id;
- char str[INET_ADDRSTRLEN];
- const char *dest_ip;
- int dest_port=0;
-
- if (device->func_type == RRH_FUNC ) {
- dest_ip = device->openair0_cfg.my_ip;
- dest_port = device->openair0_cfg.my_port;
- printf("[RRH] ip addr %s port %d\n",dest_ip, dest_port);
- } else {
- dest_ip = device->openair0_cfg.remote_ip;
- dest_port = device->openair0_cfg.remote_port;
- printf("[BBU] ip addr %s port %d\n",dest_ip, dest_port);
- }
-
- /* Open RAW socket to send on */
- if ((eth->sockfd[Mod_id] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
- perror("ETHERNET: Error opening socket");
- exit(0);
- }
-
- /* initialize destination address */
- for (i=0; i< MAX_INST; i++) {
- bzero((void *)&(eth->dest_addr[i]), sizeof(eth->dest_addr[i]));
- }
-
- // bzero((void *)dest,sizeof(struct sockaddr_in));
- eth->dest_addr[Mod_id].sin_family = AF_INET;
- inet_pton(AF_INET,dest_ip,&(eth->dest_addr[Mod_id].sin_addr.s_addr));
- eth->dest_addr[Mod_id].sin_port=htons(dest_port);
- dest_addr_len[Mod_id] = sizeof(struct sockaddr_in);
- inet_ntop(AF_INET, &(eth->dest_addr[Mod_id].sin_addr), str, INET_ADDRSTRLEN);
-
- /* if RRH, then I am the server, so bind */
- if (device->func_type == RRH_FUNC ) {
- if (bind(eth->sockfd[Mod_id],(struct sockaddr *)ð->dest_addr[Mod_id], dest_addr_len[Mod_id])<0) {
- perror("ETHERNET: Cannot bind to socket");
- exit(0);
- } else {
- printf("[RRH] binding mod_%d to %s:%d\n",Mod_id,str,ntohs(eth->dest_addr[Mod_id].sin_port));
- }
-
- } else {
- printf("[BBU] Connecting to %s:%d\n",str,ntohs(eth->dest_addr[Mod_id].sin_port));
- }
-
- return 0;
-}
-
-
-int ethernet_tune(openair0_device *device , eth_opt_t option) {
+int ethernet_tune(openair0_device *device, unsigned int option, int value) {
eth_state_t *eth = (eth_state_t*)device->priv;
int Mod_id=device->Mod_id;
-
- unsigned int sndbuf_size=0, rcvbuf_size=0;
- struct timeval snd_timeout, rcv_timeout;
+ struct timeval timeout;
struct ifreq ifr;
char system_cmd[256];
char* if_name=DEFAULT_IF;
-
- /****************** socket level options ************************/
- if (option== SND_BUF_SIZE) { /* transmit socket buffer size */
+ struct in_addr ia;
+ struct if_nameindex *ids;
+ int ret=0;
+ int i=0;
+
+ /****************** socket level options ************************/
+ switch(option) {
+ case SND_BUF_SIZE: /* transmit socket buffer size */
if (setsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_SNDBUF,
- &sndbuf_size,sizeof(sndbuf_size))) {
+ &value,sizeof(value))) {
perror("[ETHERNET] setsockopt()");
} else {
- printf( "sndbuf_size= %d bytes\n", sndbuf_size);
- }
- } else if (option== RCV_BUF_SIZE) { /* receive socket buffer size */
+ printf("send buffer size= %d bytes\n",value);
+ }
+ break;
+
+ case RCV_BUF_SIZE: /* receive socket buffer size */
if (setsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_RCVBUF,
- &rcvbuf_size,sizeof(rcvbuf_size))) {
+ &value,sizeof(value))) {
perror("[ETHERNET] setsockopt()");
} else {
- printf( "rcvbuf_size= %d bytes\n", rcvbuf_size);
+ printf("receive bufffer size= %d bytes\n",value);
}
- } else if (option==RCV_TIMEOUT) {
- rcv_timeout.tv_sec = 0;
- rcv_timeout.tv_usec = 180;//less than rt_period
+ break;
+
+ case RCV_TIMEOUT:
+ timeout.tv_sec = value/1000000000;
+ timeout.tv_usec = value%1000000000;//less than rt_period?
if (setsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_RCVTIMEO,
- (char *)&rcv_timeout,sizeof(rcv_timeout))) {
+ (char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
- printf( "rcv_timeout= %d usecs\n", rcv_timeout.tv_usec);
+ printf( "receive timeout= %d,%d sec\n",timeout.tv_sec,timeout.tv_usec);
}
- } else if (option==SND_TIMEOUT) {
- snd_timeout.tv_sec = 0;
- snd_timeout.tv_usec = 180;//less than rt_period
+ break;
+
+ case SND_TIMEOUT:
+ timeout.tv_sec = value/1000000000;
+ timeout.tv_usec = value%1000000000;//less than rt_period?
if (setsockopt(eth->sockfd[Mod_id],
SOL_SOCKET,
SO_SNDTIMEO,
- (char *)&snd_timeout,sizeof(snd_timeout))) {
+ (char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
- printf( "snd_timeout= %d usecs\n", snd_timeout.tv_usec);
+ printf( "send timeout= %d,%d sec\n",timeout.tv_sec,timeout.tv_usec);
}
- }
-
- /******************* interface level options *************************/
- else if (option==MTU_SIZE) { /* change MTU of the eth interface */
+ break;
+
+
+ /******************* interface level options *************************/
+ case MTU_SIZE: /* change MTU of the eth interface */
ifr.ifr_addr.sa_family = AF_INET;
- strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
- ifr.ifr_mtu =8960;
+ strncpy(ifr.ifr_name,eth->if_name[Mod_id], sizeof(ifr.ifr_name));
+ ifr.ifr_mtu =value;
if (ioctl(eth->sockfd[Mod_id],SIOCSIFMTU,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the MTU");
else
- printf("[ETHERNET] %s MTU size has changed to %d\n",DEFAULT_IF,ifr.ifr_mtu);
- } else if (option==TX_Q_LEN) { /* change TX queue length of eth interface */
+ printf("[ETHERNET] %s MTU size has changed to %d\n",eth->if_name[Mod_id],ifr.ifr_mtu);
+ break;
+
+ case TX_Q_LEN: /* change TX queue length of eth interface */
ifr.ifr_addr.sa_family = AF_INET;
- strncpy(ifr.ifr_name,if_name, sizeof(ifr.ifr_name));
- ifr.ifr_qlen =3000 ;
+ strncpy(ifr.ifr_name,eth->if_name[Mod_id], sizeof(ifr.ifr_name));
+ ifr.ifr_qlen =value;
if (ioctl(eth->sockfd[Mod_id],SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the txqueuelen");
else
- printf("[ETHERNET] %s txqueuelen size has changed to %d\n",DEFAULT_IF,ifr.ifr_qlen);
-
-
+ printf("[ETHERNET] %s txqueuelen size has changed to %d\n",eth->if_name[Mod_id],ifr.ifr_qlen);
+ break;
+
/******************* device level options *************************/
- } else if (option==COALESCE_PAR) {
- if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs 3",DEFAULT_IF) > 0) {
- system(system_cmd);
+ case COALESCE_PAR:
+ ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs %d",eth->if_name[Mod_id],value);
+ if (ret > 0) {
+ ret=system(system_cmd);
+ if (ret == -1) {
+ fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
+ } else {
+ printf ("[ETHERNET] status of %s is %i\n",WEXITSTATUS(ret));
+ }
printf("[ETHERNET] Coalesce parameters %s\n",system_cmd);
} else {
perror("[ETHERNET] Can't set coalesce parameters\n");
}
+ break;
- } else if (option==PAUSE_PAR ) {
- if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",DEFAULT_IF) > 0) {
- system(system_cmd);
+ case PAUSE_PAR:
+ if (value==1) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",eth->if_name[Mod_id]);
+ else if (value==0) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg on rx on tx on",eth->if_name[Mod_id]);
+ else break;
+ if (ret > 0) {
+ ret=system(system_cmd);
+ if (ret == -1) {
+ fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
+ } else {
+ printf ("[ETHERNET] status of %s is %i\n",WEXITSTATUS(ret));
+ }
printf("[ETHERNET] Pause parameters %s\n",system_cmd);
} else {
perror("[ETHERNET] Can't set pause parameters\n");
}
- } else if (option==RING_PAR ) {
- if (snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s rx 4096 tx 4096",DEFAULT_IF) > 0) {
- system(system_cmd);
+ break;
+
+ case RING_PAR:
+ ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s rx %d tx %d",eth->if_name[Mod_id],value);
+ if (ret > 0) {
+ ret=system(system_cmd);
+ if (ret == -1) {
+ fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
+ } else {
+ printf ("[ETHERNET] status of %s is %i\n",WEXITSTATUS(ret));
+ }
printf("[ETHERNET] Ring parameters %s\n",system_cmd);
} else {
perror("[ETHERNET] Can't set ring parameters\n");
}
+ break;
+ default:
+ break;
}
+
return 0;
}
-int openair0_dev_init_eth(openair0_device *device, openair0_config_t *openair0_cfg) {
+int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params ) {
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
- int card = 0;
memset(eth, 0, sizeof(eth_state_t));
- eth->buffer_size = (unsigned int)openair0_cfg[card].samples_per_packet*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
- eth->sample_rate = (unsigned int)openair0_cfg[card].sample_rate;
- device->priv = eth;
- printf("ETHERNET: Initializing openair0_device for %s ...\n", ((device->func_type == BBU_FUNC) ? "BBU": "RRH"));
+ if (eth_params->transp_preference == 1) {
+ eth->flags = ETH_RAW_MODE;
+ } else {
+ eth->flags = ETH_UDP_MODE;
+ }
+
+ printf("[ETHERNET]: Initializing openair0_device for %s ...\n", ((device->host_type == BBU_HOST) ? "BBU": "RRH"));
device->Mod_id = num_devices_eth++;
+ device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_eth_start;
device->trx_request_func = trx_eth_request;
device->trx_reply_func = trx_eth_reply;
- device->trx_write_func = trx_eth_write;
- device->trx_read_func = trx_eth_read;
device->trx_get_stats_func = trx_eth_get_stats;
device->trx_reset_stats_func = trx_eth_reset_stats;
- device->trx_end_func = trx_eth_end;
- device->trx_stop_func = trx_eth_stop;
+ device->trx_end_func = trx_eth_end;
+ device->trx_stop_func = trx_eth_stop;
device->trx_set_freq_func = trx_eth_set_freq;
device->trx_set_gains_func = trx_eth_set_gains;
-
- memcpy((void*)&device->openair0_cfg,(void*)openair0_cfg,sizeof(openair0_config_t));
+
+ if ((eth->flags & ETH_RAW_MODE) != 0 ) {
+ device->trx_write_func = trx_eth_write_raw;
+ device->trx_read_func = trx_eth_read_raw;
+ } else {
+ device->trx_write_func = trx_eth_write_udp;
+ device->trx_read_func = trx_eth_read_udp;
+ }
+
+ eth->if_name[device->Mod_id] = eth_params->local_if_name;
+ device->priv = eth;
+
+ /* device specific */
+ openair0_cfg[0].txlaunch_wait = 0;//manage when TX processing is triggered
+ openair0_cfg[0].txlaunch_wait_slotcount = 0; //manage when TX processing is triggered
+ openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
+ openair0_cfg[0].iq_txshift = eth_params->iq_txshift;// shift
+ openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance;
+
+ /* RRH does not have any information to make this configuration atm */
+ if (device->host_type == BBU_HOST) {
+ /*Note scheduling advance values valid only for case 7680000 */
+ switch ((int)openair0_cfg[0].sample_rate) {
+ case 30720000:
+ openair0_cfg[0].samples_per_packet = 4096;
+ break;
+ case 23040000:
+ openair0_cfg[0].samples_per_packet = 2048;
+ break;
+ case 15360000:
+ openair0_cfg[0].samples_per_packet = 2048;
+ break;
+ case 7680000:
+ openair0_cfg[0].samples_per_packet = 1024;
+ break;
+ case 1920000:
+ openair0_cfg[0].samples_per_packet = 256;
+ break;
+ default:
+ printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
+ exit(-1);
+ break;
+ }
+ openair0_cfg[0].tx_scheduling_advance = eth_params->tx_scheduling_advance*openair0_cfg[0].samples_per_packet;
+ }
+
+ device->openair0_cfg=&openair0_cfg[0];
return 0;
}
+
+
+/**************************************************************************************************************************
+ * DEBUGING-RELATED FUNCTIONS *
+ **************************************************************************************************************************/
+void dump_packet(char *title, unsigned char* pkt, int bytes, unsigned int tx_rx_flag) {
+
+ static int numSend = 1;
+ static int numRecv = 1;
+ int num, k;
+ char tmp[48];
+ unsigned short int cksum;
+
+ num = (tx_rx_flag)? numSend++:numRecv++;
+ for (k = 0; k < 24; k++) sprintf(tmp+k, "%02X", pkt[k]);
+ cksum = calc_csum((unsigned short *)pkt, bytes>>2);
+ printf("%s-%s (%06d): %s 0x%04X\n", title,(tx_rx_flag)? "TX":"RX", num, tmp, cksum);
+}
+
+unsigned short calc_csum (unsigned short *buf, int nwords) {
+
+ unsigned long sum;
+ for (sum = 0; nwords > 0; nwords--)
+ sum += *buf++;
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ~sum;
+}
+
+void dump_dev(openair0_device *device) {
+
+ eth_state_t *eth = (eth_state_t*)device->priv;
+
+ printf("Ethernet device interface %i configuration:\n" ,device->openair0_cfg->Mod_id);
+ printf(" Log level is %i :\n" ,device->openair0_cfg->log_level);
+ printf(" RB number: %i, sample rate: %lf \n" ,
+ device->openair0_cfg->num_rb_dl, device->openair0_cfg->sample_rate);
+ printf(" Scheduling_advance: %i, Sample_advance: %u \n" ,
+ device->openair0_cfg->tx_scheduling_advance, device->openair0_cfg->tx_sample_advance);
+ printf(" BBU configured for %i tx/%i rx channels)\n",
+ device->openair0_cfg->tx_num_channels,device->openair0_cfg->rx_num_channels);
+ printf(" Running flags: %s %s %s\n",
+ ((eth->flags & ETH_RAW_MODE) ? "RAW socket mode - ":""),
+ ((eth->flags & ETH_UDP_MODE) ? "UDP socket mode - ":""));
+ printf(" Number of iqs dumped when displaying packets: %i\n\n",eth->iqdumpcnt);
+
+}
+
+void inline dump_txcounters(openair0_device *device) {
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ printf(" Ethernet device interface %i, tx counters:\n" ,device->openair0_cfg->Mod_id);
+ printf(" Sent packets: %llu send errors: %i\n", eth->tx_count, eth->num_tx_errors);
+}
+
+void inline dump_rxcounters(openair0_device *device) {
+
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ printf(" Ethernet device interface %i rx counters:\n" ,device->openair0_cfg->Mod_id);
+ printf(" Received packets: %llu missed packets errors: %i\n", eth->rx_count, eth->num_underflows);
+}
+
+void inline dump_buff(openair0_device *device, char *buff,unsigned int tx_rx_flag, int nsamps) {
+
+ char *strptr;
+ eth_state_t *eth = (eth_state_t*)device->priv;
+ /*need to add ts number of iqs in printf need to fix dump iqs call */
+ strptr = (( tx_rx_flag == TX_FLAG) ? "TX" : "RX");
+ printf("\n %s, nsamps=%i \n" ,strptr,nsamps);
+
+ if (tx_rx_flag == 1) {
+ dump_txcounters(device);
+ printf(" First %i iqs of TX buffer\n",eth->iqdumpcnt);
+ dump_iqs(buff,eth->iqdumpcnt);
+ } else {
+ dump_rxcounters(device);
+ printf(" First %i iqs of RX buffer\n",eth->iqdumpcnt);
+ dump_iqs(buff,eth->iqdumpcnt);
+ }
+
+}
+
+void dump_iqs(char * buff, int iq_cnt) {
+ int i;
+ for (i=0;i
#include
@@ -47,71 +49,90 @@
#include
#include
-#define MAX_INST 4
-#define DEFAULT_IF "lo"
-#define BUF_SIZ 8960 /*Jumbo frame size*/
+#define MAX_INST 4
+#define DEFAULT_IF "lo"
+#define ETH_RAW_MODE 1
+#define ETH_UDP_MODE 0
+
+#define TX_FLAG 1
+#define RX_FLAG 0
+
+#define MAX_PACKET_SEQ_NUM(spp,spf) (spf/spp)
+#define MAC_HEADER_SIZE_BYTES (sizeof(struct ether_header))
+#define APP_HEADER_SIZE_BYTES (sizeof(int32_t) + sizeof(openair0_timestamp))
+#define PAYLOAD_SIZE_BYTES(nsamps) (nsamps<<2)
+#define UDP_PACKET_SIZE_BYTES(nsamps) (APP_HEADER_SIZE_BYTES + PAYLOAD_SIZE_BYTES(nsamps))
+#define RAW_PACKET_SIZE_BYTES(nsamps) (APP_HEADER_SIZE_BYTES + MAC_HEADER_SIZE_BYTES + PAYLOAD_SIZE_BYTES(nsamps))
+
+
+/*!\brief opaque ethernet data structure */
typedef struct {
-
- // opaque eth data struct
- //struct eth_if *dev;
- // An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
-
+
+ /*!\brief socket file desc */
int sockfd[MAX_INST];
- struct sockaddr_in dest_addr[MAX_INST];
-
+ /*!\brief interface name */
+ char *if_name[MAX_INST];
+ /*!\brief buffer size */
unsigned int buffer_size;
- unsigned int timeout_ns;
-
- //struct eth_metadata meta_rx;
- //struct eth_metadata meta_tx;
-
- unsigned int sample_rate;
- // time offset between transmiter timestamp and receiver timestamp;
+ /*!\brief timeout ms */
+ unsigned int rx_timeout_ms;
+ /*!\brief timeout ms */
+ unsigned int tx_timeout_ms;
+ /*!\brief runtime flags */
+ uint32_t flags;
+ /*!\ time offset between transmiter timestamp and receiver timestamp */
double tdiff;
- // use brf_time_offset to get this value
- int tx_forward_nsamps; //166 for 20Mhz
-
-
+ /*!\ calibration */
+ int tx_forward_nsamps;
+
// --------------------------------
// Debug and output control
// --------------------------------
- int num_underflows;
- int num_overflows;
- int num_seq_errors;
- int num_rx_errors;
- int num_tx_errors;
+
+ /*!\brief number of I/Q samples to be printed */
+ int iqdumpcnt;
- uint64_t tx_actual_nsamps; // actual number of samples transmitted
+ /*!\brief number of underflows in interface */
+ int num_underflows;
+ /*!\brief number of overflows in interface */
+ int num_overflows;
+ /*!\brief number of concesutive errors in interface */
+ int num_seq_errors;
+ /*!\brief number of errors in interface's receiver */
+ int num_rx_errors;
+ /*!\brief umber of errors in interface's transmitter */
+ int num_tx_errors;
+
+ /*!\brief current TX timestamp */
+ openair0_timestamp tx_current_ts;
+ /*!\brief socket file desc */
+ openair0_timestamp rx_current_ts;
+ /*!\brief actual number of samples transmitted */
+ uint64_t tx_actual_nsamps;
+ /*!\brief actual number of samples received */
uint64_t rx_actual_nsamps;
- uint64_t tx_nsamps; // number of planned samples
+ /*!\brief number of samples to be transmitted */
+ uint64_t tx_nsamps;
+ /*!\brief number of samples to be received */
uint64_t rx_nsamps;
- uint64_t tx_count; // number pf packets
+ /*!\brief number of packets transmitted */
+ uint64_t tx_count;
+ /*!\brief number of packets received */
uint64_t rx_count;
- //openair0_timestamp rx_timestamp;
} eth_state_t;
-#define ETH_META_STATUS_OVERRUN (1 << 0)
-#define ETH_META_STATUS_UNDERRUN (1 << 1)
-
-struct eth_meta_data{
- uint64_t timestamp;
- uint32_t flags;
- uint32_t status;
- unsigned int actual_count;
-};
-
/*!\brief packet header */
typedef struct {
+ /*!\brief packet sequence number max value=packets per frame*/
+ uint16_t seq_num ;
+ /*!\brief antenna port used to resynchronize */
+ uint16_t antenna_id;
/*!\brief packet's timestamp */
openair0_timestamp timestamp;
- /*!\brief variable declared for alignment purposes (sample size=32 bit) */
- int16_t not_used;
- /*!\brief antenna port used to resynchronize */
- int16_t antenna_id;
} header_t;
/*!\brief different options for ethernet tuning in socket and driver level */
@@ -138,9 +159,37 @@ typedef enum {
MAX_OPT
} eth_opt_t;
+/*
+#define SND_BUF_SIZE 1
+#define RCV_BUF_SIZE 1<<1
+#define SND_TIMEOUT 1<<2
+#define RCV_TIMEOUT 1<<3
+#define MTU_SIZE 1<<4
+#define TX_Q_LEN 1<<5
+#define RING_PAR 1<<5
+#define COALESCE_PAR 1<<6
+#define PAUSE_PAR 1<<7
+*/
+
+/*!\brief I/Q samples */
+typedef struct {
+ /*!\brief phase */
+ short i;
+ /*!\brief quadrature */
+ short q;
+} iqoai_t ;
+
+void dump_packet(char *title, unsigned char* pkt, int bytes, unsigned int tx_rx_flag);
+unsigned short calc_csum (unsigned short *buf, int nwords);
+void dump_dev(openair0_device *device);
+void inline dump_buff(openair0_device *device, char *buff,unsigned int tx_rx_flag,int nsamps);
+void inline dump_rxcounters(openair0_device *device);
+void inline dump_txcounters(openair0_device *device);
+void dump_iqs(char * buff, int iq_cnt);
-/*! \fn int ethernet_tune (openair0_device *device, eth_opt_t option)
+
+/*! \fn int ethernet_tune (openair0_device *device, unsigned int option, int value);
* \brief this function allows you to configure certain ethernet parameters in socket or device level
* \param[in] openair0 device which bears the socket
* \param[in] name of parameter to configure
@@ -148,6 +197,37 @@ typedef enum {
* \note
* @ingroup _oai
*/
-int ethernet_tune (openair0_device *device, eth_opt_t option);
-int ethernet_write_data(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc) ;
-int ethernet_read_data(openair0_device *device,openair0_timestamp *timestamp,void **buff, int nsamps,int cc);
+int ethernet_tune(openair0_device *device, unsigned int option, int value);
+
+
+
+/*! \fn int eth_socket_init_udp(openair0_device *device)
+* \brief initialization of UDP Socket to communicate with one destination
+* \param[in] *device openair device for which the socket will be created
+* \param[out]
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup _oai
+*/
+int eth_socket_init_udp(openair0_device *device);
+int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags);
+int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc);
+int eth_get_dev_conf_udp(openair0_device *device);
+
+/*! \fn static int eth_set_dev_conf_udp(openair0_device *device)
+* \brief
+* \param[in] *device openair device
+* \param[out]
+* \return 0 on success, otherwise -1
+* \note
+* @ingroup _oai
+*/
+int eth_set_dev_conf_udp(openair0_device *device);
+int eth_socket_init_raw(openair0_device *device);
+int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags);
+int trx_eth_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc);
+int eth_get_dev_conf_raw(openair0_device *device);
+int eth_set_dev_conf_raw(openair0_device *device);
+
+
+#endif
diff --git a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
index 238c94bd7e..427cd47be8 100644
--- a/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
+++ b/targets/ARCH/EXMIMO/USERSPACE/LIB/openair0_lib.c
@@ -247,7 +247,7 @@ int openair0_stop_without_reset(int card)
#define MY_RF_MODE (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
#define RF_MODE_BASE (LNA1ON + RFBBNORM)
-int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair0_cfg) {
+int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
// Initialize card
// exmimo_config_t *p_exmimo_config;
@@ -287,6 +287,8 @@ int openair0_dev_init_exmimo(openair0_device *device, openair0_config_t *openair
return(-1);
}
+ device->type = EXMIMO_DEV;
+
return(0);
}
@@ -323,6 +325,12 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
else
p_exmimo_config->framing.multicard_syncmode=SYNCMODE_SLAVE;
+ /* device specific */
+ openair0_cfg[card].txlaunch_wait = 1;//manage when TX processing is triggered
+ openair0_cfg[card].txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
+ openair0_cfg[card].iq_txshift = 4;//shift
+ openair0_cfg[card].iq_rxrescale = 15;//rescale iqs
+
if (openair0_cfg[card].sample_rate==30.72e6) {
resampling_factor = 0;
rx_filter = RXLPF10;
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/CMakeLists.txt b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/CMakeLists.txt
new file mode 100644
index 0000000000..88a021ae00
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(si5351_src_files
+ Si5351C.cpp
+)
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} ${C_FLAGS_PROCESSOR} -std=c++11 "
+)
+
+
+add_library(Si5351C STATIC ${si5351_src_files})
+target_include_directories(Si5351C PUBLIC ../lms7002m ${CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(Si5351C LMS7002M)
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.cpp
new file mode 100644
index 0000000000..88bcb74f3d
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.cpp
@@ -0,0 +1,872 @@
+/**
+@file Si5351C.cpp
+@author Lime Microsystems
+@brief Configuring of Si5351C
+*/
+
+#include "Si5351C.h"
+#include "lmsComms.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+using namespace std;
+
+#define Log(msg, type) cout << (msg) << endl;
+
+/// Splits float into fraction integers A + B/C
+void realToFrac(const float real, int &A, int &B, int &C)
+{
+ A = (int)real;
+ B = (int)((real - A) * 1048576 + 0.5);
+ C = 1048576;
+
+ int a = B;
+ int b = C;
+ int temp;
+ while( b!= 0) // greatest common divider
+ {
+ temp = a % b;
+ a = b;
+ b = temp;
+ }
+ B = B/a;
+ C = C/a;
+}
+
+/// Default configuration
+const unsigned char Si5351C::m_defaultConfiguration[] =
+{ 0,0x00,
+ 1,0x00,
+ 2,0x08,
+ 3,0x00,
+ 4,0x00,
+ 5,0x00,
+ 6,0x00,
+ 7,0x00,
+ 8,0x00,
+ 9,0x00,
+ 10,0x00,
+ 11,0x00,
+ 12,0x00,
+ 13,0x00,
+ 14,0x00,
+ 15,0x04,
+ 16,0x4F,
+ 17,0x4F,
+ 18,0x4F,
+ 19,0x4F,
+ 20,0x4F,
+ 21,0x4F,
+ 22,0x0F,
+ 23,0x0F,
+ 24,0x00,
+ 25,0x00,
+ 26,0x00,
+ 27,0x80,
+ 28,0x00,
+ 29,0x0B,
+ 30,0x2F,
+ 31,0x00,
+ 32,0x00,
+ 33,0x00,
+ 34,0x00,
+ 35,0x00,
+ 36,0x00,
+ 37,0x00,
+ 38,0x00,
+ 39,0x00,
+ 40,0x00,
+ 41,0x00,
+ 42,0x00,
+ 43,0x01,
+ 44,0x00,
+ 45,0x0D,
+ 46,0x00,
+ 47,0x00,
+ 48,0x00,
+ 49,0x00,
+ 50,0x00,
+ 51,0x01,
+ 52,0x00,
+ 53,0x0D,
+ 54,0x00,
+ 55,0x00,
+ 56,0x00,
+ 57,0x00,
+ 58,0x00,
+ 59,0x01,
+ 60,0x00,
+ 61,0x0D,
+ 62,0x00,
+ 63,0x00,
+ 64,0x00,
+ 65,0x00,
+ 66,0x00,
+ 67,0x01,
+ 68,0x00,
+ 69,0x0D,
+ 70,0x00,
+ 71,0x00,
+ 72,0x00,
+ 73,0x00,
+ 74,0x00,
+ 75,0x01,
+ 76,0x00,
+ 77,0x0D,
+ 78,0x00,
+ 79,0x00,
+ 80,0x00,
+ 81,0x00,
+ 82,0x00,
+ 83,0x01,
+ 84,0x00,
+ 85,0x0D,
+ 86,0x00,
+ 87,0x00,
+ 88,0x00,
+ 89,0x00,
+ 90,0x1E,
+ 91,0x1E,
+ 92,0x00,
+ 93,0x00,
+ 94,0x00,
+ 95,0x00,
+ 96,0x00,
+ 97,0x00,
+ 98,0x00,
+ 99,0x00,
+100,0x00,
+101,0x00,
+102,0x00,
+103,0x00,
+104,0x00,
+105,0x00,
+106,0x00,
+107,0x00,
+108,0x00,
+109,0x00,
+110,0x00,
+111,0x00,
+112,0x00,
+113,0x00,
+114,0x00,
+115,0x00,
+116,0x00,
+117,0x00,
+118,0x00,
+119,0x00,
+120,0x00,
+121,0x00,
+122,0x00,
+123,0x00,
+124,0x00,
+125,0x00,
+126,0x00,
+127,0x00,
+128,0x00,
+129,0x00,
+130,0x00,
+131,0x00,
+132,0x00,
+133,0x00,
+134,0x00,
+135,0x00,
+136,0x00,
+137,0x00,
+138,0x00,
+139,0x00,
+140,0x00,
+141,0x00,
+142,0x00,
+143,0x00,
+144,0x00,
+145,0x00,
+146,0x00,
+147,0x00,
+148,0x00,
+149,0x00,
+150,0x00,
+151,0x00,
+152,0x00,
+153,0x00,
+154,0x00,
+155,0x00,
+156,0x00,
+157,0x00,
+158,0x00,
+159,0x00,
+160,0x00,
+161,0x00,
+162,0x00,
+163,0x00,
+164,0x00,
+165,0x00,
+166,0x00,
+167,0x00,
+168,0x00,
+169,0x00,
+170,0x00,
+171,0x00,
+172,0x00,
+173,0x00,
+174,0x00,
+175,0x00,
+176,0x00,
+177,0x00,
+178,0x00,
+179,0x00,
+180,0x00,
+181,0x30,
+182,0x00,
+183,0xD2,
+184,0x60,
+185,0x60,
+186,0x00,
+187,0xC0,
+188,0x00,
+189,0x00,
+190,0x00,
+191,0x00,
+192,0x00,
+193,0x00,
+194,0x00,
+195,0x00,
+196,0x00,
+197,0x00,
+198,0x00,
+199,0x00,
+200,0x00,
+201,0x00,
+202,0x00,
+203,0x00,
+204,0x00,
+205,0x00,
+206,0x00,
+207,0x00,
+208,0x00,
+209,0x00,
+210,0x00,
+211,0x00,
+212,0x00,
+213,0x00,
+214,0x00,
+215,0x00,
+216,0x00,
+217,0x00,
+218,0x00,
+219,0x00,
+220,0x00,
+221,0x0D,
+222,0x00,
+223,0x00,
+224,0x00,
+225,0x00,
+226,0x00,
+227,0x00,
+228,0x00,
+229,0x00,
+230,0x00,
+231,0x00,
+232,0x00};
+
+// ---------------------------------------------------------------------------
+Si5351C::Si5351C()
+{
+ memset(m_newConfiguration, 0, 255);
+ for(unsigned int i=0; iIsOpen() )
+ {
+ return FAILED;
+ }
+ LMScomms::TransferStatus status;
+ status = device->TransferPacket(pkt);
+ if (status != LMScomms::TRANSFER_SUCCESS || pkt.status != STATUS_COMPLETED_CMD)
+ {
+ return FAILED;
+ }
+ return SUCCESS;
+}
+
+// ---------------------------------------------------------------------------
+/**
+ @brief Sets connection manager to use for data transferring Si5351C
+ @param mng connection manager for data transferring
+*/
+void Si5351C::Initialize(LMScomms *mng)
+{
+ assert(mng != nullptr);
+ device = mng;
+}
+
+/**
+ @brief Loads register values for Si5356A from file
+ @param FName input filename
+*/
+bool Si5351C::LoadRegValuesFromFile(string FName)
+{
+ fstream fin;
+ fin.open(FName.c_str(), ios::in);
+
+ const int len = 1024;
+ char line[len];
+
+ int addr;
+ int value;
+
+ while(!fin.eof())
+ {
+ fin.getline(line, len);
+ if( line[0] == '#')
+ continue;
+ if( strcmp(line, "#END_PROFILE") == 0)
+ break;
+ sscanf(line, "%i,%x",&addr,&value);
+ m_newConfiguration[addr] = value;
+ }
+
+ fin.close();
+ return false;
+};
+
+/** @brief Calculates multisynth dividers and VCO frequencies
+ @param clocks output clocks configuration
+ @param plls plls configurations
+ @param Fmin lowest VCO frequency
+ @param Fmax highest VCO frequency
+*/
+void Si5351C::FindVCO(Si5351_Channel *clocks, Si5351_PLL *plls, const unsigned long Fmin, const unsigned long Fmax)
+{
+ int clockCount = 8;
+ //reset output parameters
+ for(int i=0; i availableFrequenciesPLLA; //all available frequencies for VCO
+ map< unsigned long, int> availableFrequenciesPLLB; //all available frequencies for VCO
+
+ //if clk6 or clk7 is used make available frequencies according to them
+ if(clocks[6].powered || clocks[7].powered)
+ {
+ set clk6freqs;
+ set clk7freqs;
+ set sharedFreqs;
+ unsigned int mult = 6;
+ if(!clk6satisfied)
+ {
+ unsigned long freq = clocks[6].outputFreqHz;
+ while(freq <= Fmax && mult <= 254)
+ {
+ freq = clocks[6].outputFreqHz*mult;
+ if(freq >= Fmin && freq <= Fmax)
+ {
+ clk6freqs.insert(freq);
+ }
+ mult += 2;
+ }
+ }
+ mult = 6;
+ if(!clk7satisfied)
+ {
+ unsigned long freq = clocks[7].outputFreqHz;
+ while(freq <= Fmax && mult <= 254)
+ {
+ freq = clocks[7].outputFreqHz*mult;
+ if(freq >= Fmin && freq <= Fmax)
+ {
+ clk7freqs.insert(freq);
+ }
+ mult += 2;
+ }
+ }
+ bool canShare = false;
+ //find if clk6 and clk7 can share the same pll
+ for (set::iterator it6=clk6freqs.begin(); it6!=clk6freqs.end(); ++it6)
+ {
+ for (set::iterator it7=clk7freqs.begin(); it7!=clk7freqs.end(); ++it7)
+ {
+ if(*it6 == *it7)
+ {
+ canShare = true;
+ sharedFreqs.insert(*it6);
+ }
+ }
+ }
+ if(canShare) //assign PLLA for both clocks
+ {
+ clocks[6].pllSource = 0;
+ clocks[7].pllSource = 0;
+ pllAused = true;
+ for (set::iterator it=sharedFreqs.begin(); it!=sharedFreqs.end(); ++it)
+ {
+ availableFrequenciesPLLA.insert( pair (*it, 0) );
+ }
+ clk6satisfied = true;
+ clk7satisfied = true;
+ }
+ else //if clocks 6 and 7 can't share pll, assign pllA to clk6 and pllB to clk7
+ {
+ if(!clk6satisfied)
+ {
+ clocks[6].pllSource = 0;
+ clk6satisfied = true;
+ pllAused = true;
+ for (set::iterator it6=clk6freqs.begin(); it6!=clk6freqs.end(); ++it6)
+ {
+ availableFrequenciesPLLA.insert( pair(*it6, 0) );
+ }
+ }
+ if(!clk7satisfied)
+ {
+ clocks[7].pllSource = 1;
+ clk7satisfied = true;
+ pllBused = true;
+ for (set::iterator it7=clk7freqs.begin(); it7!=clk7freqs.end(); ++it7)
+ {
+ availableFrequenciesPLLB.insert( pair (*it7, 0) );
+ }
+ }
+ }
+ }
+
+ //PLLA stage, find all clocks that have integer coefficients with PLLA
+ //if pllA is not used by clk6 or clk7, fill available frequencies according to clk1-clk5 clocks
+ if( availableFrequenciesPLLA.size() == 0 && !pllAused)
+ {
+ for(int i=0; i<6; ++i)
+ {
+ unsigned long freq = clocks[i].outputFreqHz > Fmin ? clocks[i].outputFreqHz : (clocks[i].outputFreqHz*((Fmin/clocks[i].outputFreqHz) + ((Fmin%clocks[i].outputFreqHz)!=0)));
+ while(freq >= Fmin && freq <= Fmax)
+ {
+ //add all output frequency multiples that are in VCO interval
+ availableFrequenciesPLLA.insert( pair (freq, 0));
+ freq += clocks[i].outputFreqHz;
+ }
+ }
+ }
+
+ unsigned int bestScore = 0; //score shows how many outputs have integer dividers
+ //calculate scores for all available frequencies
+ unsigned long bestVCOA = 0;
+ for (map::iterator it=availableFrequenciesPLLA.begin(); it!=availableFrequenciesPLLA.end(); ++it)
+ {
+ for(int i=0; i<8; ++i)
+ {
+ if(clocks[i].outputFreqHz == 0 || !clocks[i].powered)
+ continue;
+
+ if( (it->first % clocks[i].outputFreqHz) == 0)
+ {
+ it->second = it->second+1;
+ }
+ }
+ if(it->second >= bestScore)
+ {
+ bestScore = it->second;
+ bestVCOA = it->first;
+ }
+ }
+ //scores calculated
+ //cout << "PLLA stage: " << endl;
+ //cout << "best score: " << bestScore << " best VCO: " << bestVCOA << endl;
+ plls[0].VCO_Hz = bestVCOA;
+ plls[0].feedbackDivider = (double)bestVCOA/plls[0].inputFreqHz;
+
+ for(int i=0; i Fmin ? clocks[i].outputFreqHz : (clocks[i].outputFreqHz*((Fmin/clocks[i].outputFreqHz) + ((Fmin%clocks[i].outputFreqHz)!=0)));
+ while(freq >= Fmin && freq <= Fmax)
+ {
+ availableFrequenciesPLLB.insert( pair (freq, 0));
+ freq += clocks[i].outputFreqHz;
+ }
+ }
+ }
+
+ bestScore = 0;
+ //calculate scores for all available frequencies
+ unsigned long bestVCOB = 0;
+ for (map::iterator it=availableFrequenciesPLLB.begin(); it!=availableFrequenciesPLLB.end(); ++it)
+ {
+ for(int i=0; i<8; ++i)
+ {
+ if(clocks[i].outputFreqHz == 0 || !clocks[i].powered)
+ continue;
+
+ if( (it->first % clocks[i].outputFreqHz) == 0)
+ {
+ it->second = it->second+1;
+ }
+ }
+ if(it->second >= bestScore)
+ {
+ bestScore = it->second;
+ bestVCOB = it->first;
+ }
+ }
+ //scores calculated
+// cout << "PLLB stage: " << endl;
+// cout << "best score: " << bestScore << " best VCO: " << bestVCOB << endl;
+ if(bestVCOB == 0) //just in case if pllb is not used make it the same frequency as plla
+ bestVCOB = bestVCOA;
+ plls[1].VCO_Hz = bestVCOB;
+ plls[1].feedbackDivider = (double)bestVCOB/plls[0].inputFreqHz;
+ for(int i=0; i> 8;
+ m_newConfiguration[addr+1] = MSX_P3;
+
+ m_newConfiguration[addr+2] = 0;
+ m_newConfiguration[addr+2] |= (MSX_P1 >> 16 ) & 0x03;
+ m_newConfiguration[addr+3] = MSX_P1 >> 8;
+ m_newConfiguration[addr+4] = MSX_P1;
+
+ m_newConfiguration[addr+5] = 0;
+ m_newConfiguration[addr+5] = (MSX_P2 >> 16) & 0x0F;
+ m_newConfiguration[addr+5] |= (MSX_P3 >> 16) << 4;
+
+ m_newConfiguration[addr+6] = MSX_P2;
+ m_newConfiguration[addr+7] = MSX_P2 >> 8;
+ }
+ else if( CLK[i].outputFreqHz <= 160000000) // AVAILABLE ONLY ON 0-5 MULTISYNTHS
+ {
+ Log("Si5351C - clock configuring for more than 150 MHz not implemented\n", LOG_ERROR);
+ return FAILED;
+ }
+ }
+ else // CLK6 and CLK7 only integer mode
+ {
+ if(CLK[i].outputFreqHz <= 150000000)
+ {
+ if(i==6)
+ {
+ m_newConfiguration[90] = DivA;
+ if(DivA%2 != 0)
+ {
+ Log("Si5351C - CLK6 multisynth divider is not even integer\n", LOG_ERROR);
+ return FAILED;
+ }
+ }
+ else
+ {
+ m_newConfiguration[91] = DivA;
+ if(DivA%2 != 0)
+ {
+ Log("Si5351C - CLK7 multisynth divider is not even integer\n", LOG_ERROR);
+ return FAILED;
+ }
+ }
+ }
+ else if( CLK[i].outputFreqHz <= 160000000) // AVAILABLE ONLY ON 0-5 MULTISYNTHS
+ {
+ Log("Si5351C - clock configuring for more than 150 MHz not implemented\n", LOG_ERROR);
+ return FAILED;
+ }
+ }
+ }
+
+ //configure pll
+ //set input clk source
+ m_newConfiguration[15] = m_newConfiguration[15] & 0xF3;
+ m_newConfiguration[15] |= (PLL[0].CLK_SRC & 1) << 2;
+ m_newConfiguration[15] |= (PLL[1].CLK_SRC & 1) << 3;
+ for(int i=0; i<2; ++i)
+ {
+ addr = 26+i*8;
+ if(PLL[i].feedbackDivider < 15 || PLL[i].feedbackDivider > 90)
+ {
+ Log("Si5351C - VCO frequency divider out of range [15:90].\n", LOG_ERROR);
+ return FAILED;
+ }
+ if( PLL[i].VCO_Hz < 600000000 || PLL[i].VCO_Hz > 900000000)
+ {
+ Log("Si5351C - Can't calculate valid VCO frequency.\n", LOG_ERROR);
+ return FAILED;
+ }
+ ss.clear();
+ ss.str(string());
+ ss << "Si5351C : VCO" << (i==0 ? "A" : "B") << " = " << PLL[i].VCO_Hz/1000000.0 << " MHz";
+
+ //calculate MSNx_P1, MSNx_P2, MSNx_P3
+ int MSNx_P1;
+ int MSNx_P2;
+ int MSNx_P3;
+
+ int DivA;
+ int DivB;
+ int DivC;
+ realToFrac(PLL[i].feedbackDivider, DivA, DivB, DivC);
+ ss << " Feedback Divider " << DivA << " " << DivB << "/" << DivC << endl;
+ Log(ss.str(), LOG_INFO);
+
+ MSNx_P1 = 128 * DivA + floor(128 * ( (float)DivB/DivC)) - 512;
+ MSNx_P2 = 128 * DivB - DivC * floor( 128 * DivB/DivC );
+ MSNx_P3 = DivC;
+
+ m_newConfiguration[addr+4] = MSNx_P1;
+ m_newConfiguration[addr+3] = MSNx_P1 >> 8;
+ m_newConfiguration[addr+2] = MSNx_P1 >> 16;
+
+ m_newConfiguration[addr+7] = MSNx_P2;
+ m_newConfiguration[addr+6] = MSNx_P2 >> 8;
+ m_newConfiguration[addr+5] = 0;
+ m_newConfiguration[addr+5] = (MSNx_P2 >> 16) & 0x0F;
+
+ m_newConfiguration[addr+5] |= (MSNx_P3 >> 16) << 4;
+ m_newConfiguration[addr+1] |= MSNx_P3;
+ m_newConfiguration[addr] |= MSNx_P3 >> 8;
+ }
+ return SUCCESS;
+}
+
+/** @brief Sets output clock parameters
+ @param id clock id 0-CLK0 1-CLK1 ...
+ @param fOut_Hz output frequency in Hz
+ @param enabled is this output powered
+ @param inverted invert clock
+*/
+void Si5351C::SetClock(unsigned char id, unsigned long fOut_Hz, bool enabled, bool inverted)
+{
+ if( id < 8)
+ {
+ if(fOut_Hz < 8000 || fOut_Hz > 160000000)
+ {
+ stringstream ss;
+ ss << "Si5351C - CLK" << (int)id << " output frequency must be between 8kHz and 160MHz. fOut_MHz = " << fOut_Hz/1000000.0 << endl;
+ Log(ss.str(), LOG_ERROR);
+ return;
+ }
+ CLK[id].powered = enabled;
+ CLK[id].inverted = inverted;
+ CLK[id].outputFreqHz = fOut_Hz;
+ }
+}
+
+/** @brief Sets PLL input frequency
+ @param id PLL id 0-PLLA 1-PLLB
+ @param CLKIN_Hz clock input in Hz
+*/
+void Si5351C::SetPLL(unsigned char id, unsigned long CLKIN_Hz, int CLK_SRC)
+{
+ if (id < 2)
+ {
+ PLL[id].inputFreqHz = CLKIN_Hz;
+ PLL[id].CLK_SRC = CLK_SRC;
+ }
+}
+
+/** @brief Resets configuration registers to default values
+*/
+void Si5351C::Reset()
+{
+ memset(m_newConfiguration, 0, 255);
+ for(unsigned int i=0; iTransferPacket(pkt);
+ if (status != LMScomms::TRANSFER_SUCCESS || pkt.status != STATUS_COMPLETED_CMD)
+ {
+ return stat;
+ }
+
+ stat.sys_init = (pkt.inBuffer[0] >> 7);
+ stat.lol_b = (pkt.inBuffer[0] >> 6) & 0x1;
+ stat.lol_a = (pkt.inBuffer[0] >> 5) & 0x1;
+ stat.los = (pkt.inBuffer[0] >> 4) & 0x1;
+ stat.sys_init_stky = (pkt.inBuffer[1] >> 7);
+ stat.lol_b_stky = (pkt.inBuffer[1] >> 6) & 0x1;
+ stat.lol_a_stky = (pkt.inBuffer[1] >> 5) & 0x1;
+ stat.los_stky = (pkt.inBuffer[1] >> 4) & 0x1;
+ return stat;
+}
+
+Si5351C::Status Si5351C::ClearStatus()
+{
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_SI5351_WR;
+ pkt.outBuffer.push_back(1);
+ pkt.outBuffer.push_back(0x0);
+ LMScomms::TransferStatus status;
+ status = device->TransferPacket(pkt);
+ if (status != LMScomms::TRANSFER_SUCCESS || pkt.status != STATUS_COMPLETED_CMD)
+ return FAILED;
+ return SUCCESS;
+}
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.h b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.h
new file mode 100644
index 0000000000..971a2d1d69
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/Si5351C/Si5351C.h
@@ -0,0 +1,100 @@
+/**
+@file Si5351C.h
+@brief Header for Si5351C.cpp
+@author Lime Microsystems
+*/
+
+#ifndef SI5351C_MODULE
+#define SI5351C_MODULE
+
+#include
+#include
+using namespace std;
+//---------------------------------------------------------------------------
+
+enum eSi_CLOCK_INPUT
+{
+ Si_CLKIN,
+ Si_XTAL,
+ Si_CMOS
+};
+
+struct Si5351_Channel
+{
+ Si5351_Channel() : outputDivider(1), outputFreqHz(1), multisynthDivider(1), pllSource(0),
+ phaseOffset(0), powered(true), inverted(false), int_mode(false) {};
+ int outputDivider;
+ unsigned long outputFreqHz;
+ float multisynthDivider;
+ int pllSource;
+ float phaseOffset;
+ bool powered;
+ bool inverted;
+ bool int_mode;
+};
+
+struct Si5351_PLL
+{
+ Si5351_PLL() : inputFreqHz(0), VCO_Hz(0), feedbackDivider(0), CLKIN_DIV(1), CLK_SRC(1) {}
+ unsigned long inputFreqHz;
+ float VCO_Hz;
+ float feedbackDivider;
+ int CLKIN_DIV;
+ int CLK_SRC; //0-XTAL, 1-CLKIN
+};
+
+class LMScomms;
+class Si5351C
+{
+public:
+ enum Status
+ {
+ SUCCESS,
+ FAILED,
+ };
+
+ struct StatusBits
+ {
+ StatusBits() : sys_init(0), sys_init_stky(0), lol_b(0), lol_b_stky(0), lol_a(0), lol_a_stky(0), los(0), los_stky(0)
+ {
+
+ }
+ int sys_init;
+ int sys_init_stky;
+ int lol_b;
+ int lol_b_stky;
+ int lol_a;
+ int lol_a_stky;
+ int los;
+ int los_stky;
+ };
+
+ StatusBits GetStatusBits();
+ Status ClearStatus();
+
+ Si5351C();
+ ~Si5351C();
+ void Initialize(LMScomms *mng);
+ bool LoadRegValuesFromFile(string FName);
+
+ void SetPLL(unsigned char id, unsigned long CLKIN_Hz, int CLK_SRC);
+ void SetClock(unsigned char id, unsigned long fOut_Hz, bool enabled = true, bool inverted = false);
+
+ Status UploadConfiguration();
+ Status ConfigureClocks();
+ void Reset();
+
+private:
+ void FindVCO(Si5351_Channel *clocks, Si5351_PLL *plls, const unsigned long Fmin, const unsigned long Fmax);
+ LMScomms *device;
+
+ Si5351_PLL PLL[2];
+ Si5351_Channel CLK[8];
+
+ static const unsigned char m_defaultConfiguration[];
+ unsigned char m_newConfiguration[255];
+
+
+};
+
+#endif // SI5351C_MODULE
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/CMakeLists.txt b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/CMakeLists.txt
new file mode 100644
index 0000000000..cea22ac829
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/CMakeLists.txt
@@ -0,0 +1,63 @@
+cmake_minimum_required(VERSION 2.8)
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE TYPE INTERNAL FORCE)
+project("lms7api")
+#include modules for finding FFTW and CyAPI
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+cmake_policy(SET CMP0015 OLD)
+if(${CMAKE_MAJOR_VERSION} GREATER 2)
+ cmake_policy(SET CMP0043 NEW)
+endif()
+ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+if(CMAKE_COMPILER_IS_GNUCXX)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+endif()
+
+# set up include-directories
+include_directories(
+ "${PROJECT_SOURCE_DIR}"
+ "${PROJECT_BINARY_DIR}"
+ cpp-feather-ini-parser
+ )
+
+set(LMS7002M_src_files
+ LMS7002M.cpp
+ LMS7002M_parameters.cpp
+ LMS7002M_statuses.cpp
+ LMS7002M_filtersCalibration.cpp
+ lmsComms.cpp
+ LMS7002M_RegistersMap.cpp
+)
+
+set(ENABLE_USB_CONNECTION "YES" CACHE BOOL INTERNAL)
+set(ENABLE_SPI_CONNECTION "NO" CACHE BOOL INTERNAL)
+set(CONNECTION_MANAGER_DIR connectionManager)
+set(connectionManager_src_files
+ ${CONNECTION_MANAGER_DIR}/ConnectionManager.cpp
+ ${CONNECTION_MANAGER_DIR}/ConnectionCOM.cpp
+ ${CONNECTION_MANAGER_DIR}/ConnectionManager.h
+ ${CONNECTION_MANAGER_DIR}/ConnectionCOM.h
+)
+if(ENABLE_USB_CONNECTION)
+ list(APPEND connectionManager_src_files ${CONNECTION_MANAGER_DIR}/ConnectionUSB.cpp ${CONNECTION_MANAGER_DIR}/ConnectionUSB.h)
+ add_definitions(-DENABLE_USB_CONNECTION)
+endif()
+if(ENABLE_SPI_CONNECTION)
+ list(APPEND connectionManager_src_files ${CONNECTION_MANAGER_DIR}/ConnectionSPI.cpp ${CONNECTION_MANAGER_DIR}/ConnectionSPI.h)
+ add_definitions(-DENABLE_SPI_CONNECTION)
+endif()
+
+add_library(LMS7002M STATIC ${LMS7002M_src_files} ${connectionManager_src_files})
+target_include_directories(LMS7002M PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+
+if(WIN32 AND ENABLE_USB_CONNECTION)
+ find_package(CyAPI REQUIRED)
+ LINK_DIRECTORIES(${CYAPI_LIBRARIES})
+ include_directories(${CYAPI_INCLUDE_DIRS})
+ set(CONNECTION_MANAGER_LIBS ${CYAPI_LIBRARIES} SetupAPI)
+ target_link_libraries(LMS7002M ${CONNECTION_MANAGER_LIBS})
+endif()
+if(UNIX AND ENABLE_USB_CONNECTION)
+ set(CONNECTION_MANAGER_LIBS usb-1.0 -lpthread)
+ target_link_libraries(LMS7002M ${CONNECTION_MANAGER_LIBS})
+endif()
+
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.cpp
new file mode 100644
index 0000000000..ded70e114f
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.cpp
@@ -0,0 +1,2612 @@
+/**
+@file LMS7002M.cpp
+@author Lime Microsystems (www.limemicro.com)
+@brief Implementation of LMS7002M transceiver configuring
+*/
+
+#include "LMS7002M.h"
+#include
+#include
+#include "lmsComms.h"
+#include "INI.h"
+#include
+#include
+#include
+#include "LMS7002M_RegistersMap.h"
+
+#include
+#include
+
+float_type LMS7002M::gVCO_frequency_table[3][2] = { { 3800, 5222 }, { 4961, 6754 }, {6306, 7714} };
+float_type LMS7002M::gCGEN_VCO_frequencies[2] = {2000, 2700};
+
+///define for parameter enumeration if prefix might be needed
+#define LMS7param(id) id
+
+//module addresses needs to be sorted in ascending order
+const uint16_t LMS7002M::readOnlyRegisters[] = { 0x002F, 0x008C, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x0123, 0x0209, 0x020A, 0x020B, 0x040E, 0x040F };
+const uint16_t LMS7002M::readOnlyRegistersMasks[] = { 0x0000, 0x0FFF, 0x007F, 0x0000, 0x0000, 0x0000, 0x0000, 0x003F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
+
+/** @brief Simple logging function to print status messages
+ @param text message to print
+ @param type message type for filtering specific information
+*/
+void LMS7002M::Log(const char* text, LogType type)
+{
+ switch(type)
+ {
+ case LOG_INFO:
+ printf("%s\n", text);
+ break;
+ case LOG_WARNING:
+ printf("Warning: %s\n", text);
+ break;
+ case LOG_ERROR:
+ printf("ERROR: %s\n", text);
+ break;
+ case LOG_DATA:
+ printf("DATA: %s\n", text);
+ break;
+ }
+}
+
+LMS7002M::LMS7002M() : controlPort(NULL), mRegistersMap(new LMS7002M_RegistersMap())
+{
+ mRefClkSXR_MHz = 30.72;
+ mRefClkSXT_MHz = 30.72;
+}
+
+/** @brief Creates LMS7002M main control object, it requires LMScomms to communicate with chip
+ @param controlPort data connection for controlling LMS7002 chip registers
+*/
+LMS7002M::LMS7002M(LMScomms* controlPort) :
+ controlPort(controlPort), mRegistersMap(new LMS7002M_RegistersMap())
+{
+ mRefClkSXR_MHz = 30.72;
+ mRefClkSXT_MHz = 30.72;
+
+ //memory intervals for registers tests and calibration algorithms
+ MemorySectionAddresses[LimeLight][0] = 0x0020;
+ MemorySectionAddresses[LimeLight][1] = 0x002F;
+ MemorySectionAddresses[EN_DIR][0] = 0x0081;
+ MemorySectionAddresses[EN_DIR][1] = 0x0081;
+ MemorySectionAddresses[AFE][0] = 0x0082;
+ MemorySectionAddresses[AFE][1] = 0x0082;
+ MemorySectionAddresses[BIAS][0] = 0x0084;
+ MemorySectionAddresses[BIAS][1] = 0x0084;
+ MemorySectionAddresses[XBUF][0] = 0x0085;
+ MemorySectionAddresses[XBUF][1] = 0x0085;
+ MemorySectionAddresses[CGEN][0] = 0x0086;
+ MemorySectionAddresses[CGEN][1] = 0x008C;
+ MemorySectionAddresses[LDO][0] = 0x0092;
+ MemorySectionAddresses[LDO][1] = 0x00A7;
+ MemorySectionAddresses[BIST][0] = 0x00A8;
+ MemorySectionAddresses[BIST][1] = 0x00AC;
+ MemorySectionAddresses[CDS][0] = 0x00AD;
+ MemorySectionAddresses[CDS][1] = 0x00AE;
+ MemorySectionAddresses[TRF][0] = 0x0100;
+ MemorySectionAddresses[TRF][1] = 0x0104;
+ MemorySectionAddresses[TBB][0] = 0x0105;
+ MemorySectionAddresses[TBB][1] = 0x010A;
+ MemorySectionAddresses[RFE][0] = 0x010C;
+ MemorySectionAddresses[RFE][1] = 0x0114;
+ MemorySectionAddresses[RBB][0] = 0x0115;
+ MemorySectionAddresses[RBB][1] = 0x011A;
+ MemorySectionAddresses[SX][0] = 0x011C;
+ MemorySectionAddresses[SX][1] = 0x0124;
+ MemorySectionAddresses[TxTSP][0] = 0x0200;
+ MemorySectionAddresses[TxTSP][1] = 0x020C;
+ MemorySectionAddresses[TxNCO][0] = 0x0240;
+ MemorySectionAddresses[TxNCO][1] = 0x0261;
+ MemorySectionAddresses[TxGFIR1][0] = 0x0280;
+ MemorySectionAddresses[TxGFIR1][1] = 0x02A7;
+ MemorySectionAddresses[TxGFIR2][0] = 0x02C0;
+ MemorySectionAddresses[TxGFIR2][1] = 0x02E7;
+ MemorySectionAddresses[TxGFIR3a][0] = 0x0300;
+ MemorySectionAddresses[TxGFIR3a][1] = 0x0327;
+ MemorySectionAddresses[TxGFIR3b][0] = 0x0340;
+ MemorySectionAddresses[TxGFIR3b][1] = 0x0367;
+ MemorySectionAddresses[TxGFIR3c][0] = 0x0380;
+ MemorySectionAddresses[TxGFIR3c][1] = 0x03A7;
+ MemorySectionAddresses[RxTSP][0] = 0x0400;
+ MemorySectionAddresses[RxTSP][1] = 0x040F;
+ MemorySectionAddresses[RxNCO][0] = 0x0440;
+ MemorySectionAddresses[RxNCO][1] = 0x0461;
+ MemorySectionAddresses[RxGFIR1][0] = 0x0480;
+ MemorySectionAddresses[RxGFIR1][1] = 0x04A7;
+ MemorySectionAddresses[RxGFIR2][0] = 0x04C0;
+ MemorySectionAddresses[RxGFIR2][1] = 0x04E7;
+ MemorySectionAddresses[RxGFIR3a][0] = 0x0500;
+ MemorySectionAddresses[RxGFIR3a][1] = 0x0527;
+ MemorySectionAddresses[RxGFIR3b][0] = 0x0540;
+ MemorySectionAddresses[RxGFIR3b][1] = 0x0567;
+ MemorySectionAddresses[RxGFIR3c][0] = 0x0580;
+ MemorySectionAddresses[RxGFIR3c][1] = 0x05A7;
+
+ mRegistersMap->InitializeDefaultValues(LMS7parameterList);
+}
+
+LMS7002M::~LMS7002M()
+{
+
+}
+
+/** @brief Sends reset signal to chip, after reset enables B channel controls
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::ResetChip()
+{
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_LMS7002_RST;
+ pkt.outBuffer.push_back(LMS_RST_PULSE);
+ controlPort->TransferPacket(pkt);
+ if (pkt.status == STATUS_COMPLETED_CMD)
+ {
+ Modify_SPI_Reg_bits(LMS7param(MIMO_SISO), 0); //enable B channel after reset
+ return LIBLMS7_SUCCESS;
+ }
+ else
+ return LIBLMS7_FAILURE;
+}
+
+liblms7_status LMS7002M::LoadConfigLegacyFile(const char* filename)
+{
+ ifstream f(filename);
+ if (f.good() == false) //file not found
+ {
+ f.close();
+ return LIBLMS7_FILE_NOT_FOUND;
+ }
+ f.close();
+ uint16_t addr = 0;
+ uint16_t value = 0;
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC)); //remember used channel
+ liblms7_status status;
+ typedef INI ini_t;
+ ini_t parser(filename, true);
+ if (parser.select("FILE INFO") == false)
+ return LIBLMS7_FILE_INVALID_FORMAT;
+
+ string type = "";
+ type = parser.get("type", "undefined");
+ stringstream ss;
+ if (type.find("LMS7002 configuration") == string::npos)
+ {
+ ss << "File " << filename << " not recognized" << endl;
+ return LIBLMS7_FILE_INVALID_FORMAT;
+ }
+
+ int fileVersion = 0;
+ fileVersion = parser.get("version", 0);
+
+ vector addrToWrite;
+ vector dataToWrite;
+ if (fileVersion == 1)
+ {
+ if (parser.select("Reference clocks"))
+ {
+ mRefClkSXR_MHz = parser.get("SXR reference frequency MHz", 30.72);
+ mRefClkSXT_MHz = parser.get("SXT reference frequency MHz", 30.72);
+ }
+
+ if (parser.select("LMS7002 registers ch.A") == true)
+ {
+ ini_t::sectionsit_t section = parser.sections.find("LMS7002 registers ch.A");
+
+ uint16_t x0020_value = 0;
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); //select A channel
+ for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++)
+ {
+ sscanf(pairs->first.c_str(), "%hx", &addr);
+ sscanf(pairs->second.c_str(), "%hx", &value);
+ if (addr == LMS7param(MAC).address) //skip register containing channel selection
+ {
+ x0020_value = value;
+ continue;
+ }
+ addrToWrite.push_back(addr);
+ dataToWrite.push_back(value);
+ }
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+
+ //parse FCW or PHO
+ if (parser.select("NCO Rx ch.A") == true)
+ {
+ char varname[64];
+ int mode = Get_SPI_Reg_bits(LMS7param(MODE_RX));
+ if (mode == 0) //FCW
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "FCW%02i", i);
+ SetNCOFrequency(LMS7002M::Rx, i, parser.get(varname, 0.0));
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "PHO%02i", i);
+ SetNCOPhaseOffset(LMS7002M::Rx, i, parser.get(varname, 0.0));
+ }
+ }
+ }
+ if (parser.select("NCO Tx ch.A") == true)
+ {
+ char varname[64];
+ int mode = Get_SPI_Reg_bits(LMS7param(MODE_TX));
+ if (mode == 0) //FCW
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "FCW%02i", i);
+ SetNCOFrequency(LMS7002M::Tx, i, parser.get(varname, 0.0));
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "PHO%02i", i);
+ SetNCOPhaseOffset(LMS7002M::Tx, i, parser.get(varname, 0.0));
+ }
+ }
+ }
+ status = SPI_write(0x0020, x0020_value);
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+ }
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+
+ if (parser.select("LMS7002 registers ch.B") == true)
+ {
+ addrToWrite.clear();
+ dataToWrite.clear();
+ ini_t::sectionsit_t section = parser.sections.find("LMS7002 registers ch.B");
+ for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++)
+ {
+ sscanf(pairs->first.c_str(), "%hx", &addr);
+ sscanf(pairs->second.c_str(), "%hx", &value);
+ addrToWrite.push_back(addr);
+ dataToWrite.push_back(value);
+ }
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); //select B channel
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+
+ //parse FCW or PHO
+ if (parser.select("NCO Rx ch.B") == true)
+ {
+ char varname[64];
+ int mode = Get_SPI_Reg_bits(LMS7param(MODE_RX));
+ if (mode == 0) //FCW
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "FCW%02i", i);
+ SetNCOFrequency(LMS7002M::Rx, i, parser.get(varname, 0.0));
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "PHO%02i", i);
+ SetNCOPhaseOffset(LMS7002M::Rx, i, parser.get(varname, 0.0));
+ }
+ }
+ }
+ if (parser.select("NCO Tx ch.A") == true)
+ {
+ char varname[64];
+ int mode = Get_SPI_Reg_bits(LMS7param(MODE_TX));
+ if (mode == 0) //FCW
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "FCW%02i", i);
+ SetNCOFrequency(LMS7002M::Tx, i, parser.get(varname, 0.0));
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ sprintf(varname, "PHO%02i", i);
+ SetNCOPhaseOffset(LMS7002M::Tx, i, parser.get(varname, 0.0));
+ }
+ }
+ }
+ }
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ return LIBLMS7_SUCCESS;
+ }
+ else
+ return LIBLMS7_FILE_INVALID_FORMAT;
+ return LIBLMS7_FAILURE;
+}
+
+/** @brief Reads configuration file and uploads registers to chip
+ @param filename Configuration source file
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::LoadConfig(const char* filename)
+{
+ ifstream f(filename);
+ if (f.good() == false) //file not found
+ {
+ f.close();
+ return LIBLMS7_FILE_NOT_FOUND;
+ }
+ f.close();
+ uint16_t addr = 0;
+ uint16_t value = 0;
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC)); //remember used channel
+
+ liblms7_status status;
+ typedef INI ini_t;
+ ini_t parser(filename, true);
+ if (parser.select("file_info") == false)
+ {
+ //try loading as legacy format
+ status = LoadConfigLegacyFile(filename);
+ Modify_SPI_Reg_bits(MAC, 1);
+ return status;
+ }
+ string type = "";
+ type = parser.get("type", "undefined");
+ stringstream ss;
+ if (type.find("lms7002m_minimal_config") == string::npos)
+ {
+ ss << "File " << filename << " not recognized" << endl;
+ return LIBLMS7_FILE_INVALID_FORMAT;
+ }
+
+ int fileVersion = 0;
+ fileVersion = parser.get("version", 0);
+
+ vector addrToWrite;
+ vector dataToWrite;
+
+ if (fileVersion == 1)
+ {
+ if(parser.select("lms7002_registers_a") == true)
+ {
+ ini_t::sectionsit_t section = parser.sections.find("lms7002_registers_a");
+
+ uint16_t x0020_value = 0;
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); //select A channel
+ for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++)
+ {
+ sscanf(pairs->first.c_str(), "%hx", &addr);
+ sscanf(pairs->second.c_str(), "%hx", &value);
+ if (addr == LMS7param(MAC).address) //skip register containing channel selection
+ {
+ x0020_value = value;
+ continue;
+ }
+ addrToWrite.push_back(addr);
+ dataToWrite.push_back(value);
+ }
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+ status = SPI_write(0x0020, x0020_value);
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+ }
+
+ if (parser.select("lms7002_registers_b") == true)
+ {
+ addrToWrite.clear();
+ dataToWrite.clear();
+ ini_t::sectionsit_t section = parser.sections.find("lms7002_registers_b");
+ for (ini_t::keysit_t pairs = section->second->begin(); pairs != section->second->end(); pairs++)
+ {
+ sscanf(pairs->first.c_str(), "%hx", &addr);
+ sscanf(pairs->second.c_str(), "%hx", &value);
+ addrToWrite.push_back(addr);
+ dataToWrite.push_back(value);
+ }
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); //select B channel
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS && status != LIBLMS7_NOT_CONNECTED)
+ return status;
+ }
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+
+ parser.select("reference_clocks");
+ mRefClkSXR_MHz = parser.get("sxr_ref_clk_mhz", 30.72);
+ mRefClkSXT_MHz = parser.get("sxt_ref_clk_mhz", 30.72);
+ }
+
+ Modify_SPI_Reg_bits(MAC, 1);
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Reads all registers from chip and saves to file
+ @param filename destination filename
+ @return 0-success, other failure
+*/
+liblms7_status LMS7002M::SaveConfig(const char* filename)
+{
+ liblms7_status status;
+ typedef INI<> ini_t;
+ ini_t parser(filename, true);
+ parser.create("file_info");
+ parser.set("type", "lms7002m_minimal_config");
+ parser.set("version", 1);
+
+ char addr[80];
+ char value[80];
+
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+
+ vector addrToRead;
+ for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
+ for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
+ addrToRead.push_back(addr);
+ vector dataReceived;
+ dataReceived.resize(addrToRead.size(), 0);
+
+ parser.create("lms7002_registers_a");
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ {
+ dataReceived[i] = Get_SPI_Reg_bits(addrToRead[i], 15, 0, false);
+ sprintf(addr, "0x%04X", addrToRead[i]);
+ sprintf(value, "0x%04X", dataReceived[i]);
+ parser.set(addr, value);
+ }
+
+ parser.create("lms7002_registers_b");
+ addrToRead.clear(); //add only B channel addresses
+ for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
+ for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
+ if (addr >= 0x0100)
+ addrToRead.push_back(addr);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ {
+ dataReceived[i] = Get_SPI_Reg_bits(addrToRead[i], 15, 0, false);
+ sprintf(addr, "0x%04X", addrToRead[i]);
+ sprintf(value, "0x%04X", dataReceived[i]);
+ parser.set(addr, value);
+ }
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //retore previously used channel
+
+ parser.create("reference_clocks");
+ parser.set("sxt_ref_clk_mhz", mRefClkSXT_MHz);
+ parser.set("sxr_ref_clk_mhz", mRefClkSXR_MHz);
+ parser.save(filename);
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Returns reference clock in MHz used for SXT or SXR
+ @param Tx transmitter or receiver selection
+*/
+float_type LMS7002M::GetReferenceClk_SX(bool tx)
+{
+ return tx ? mRefClkSXT_MHz : mRefClkSXR_MHz;
+}
+
+/** @return Current CLKGEN frequency in MHz
+ Returned frequency depends on reference clock used for Receiver
+*/
+float_type LMS7002M::GetFrequencyCGEN_MHz()
+{
+ float_type dMul = (mRefClkSXR_MHz/2.0)/(Get_SPI_Reg_bits(LMS7param(DIV_OUTCH_CGEN))+1); //DIV_OUTCH_CGEN
+ uint16_t gINT = Get_SPI_Reg_bits(0x0088, 13, 0); //read whole register to reduce SPI transfers
+ uint32_t gFRAC = ((gINT & 0xF) * 65536) | Get_SPI_Reg_bits(0x0087, 15, 0);
+ return dMul * (((gINT>>4) + 1 + gFRAC/1048576.0));
+}
+
+/** @brief Returns TSP reference frequency
+ @param tx TxTSP or RxTSP selection
+ @return TSP reference frequency in MHz
+*/
+float_type LMS7002M::GetReferenceClk_TSP_MHz(bool tx)
+{
+ float_type cgenFreq = GetFrequencyCGEN_MHz();
+ float_type clklfreq = cgenFreq/pow(2.0, Get_SPI_Reg_bits(LMS7param(CLKH_OV_CLKL_CGEN)));
+ if(Get_SPI_Reg_bits(LMS7param(EN_ADCCLKH_CLKGN)) == 0)
+ return tx ? clklfreq : cgenFreq/4.0;
+ else
+ return tx ? cgenFreq : clklfreq/4.0;
+}
+
+/** @brief Sets CLKGEN frequency, calculations use receiver'r reference clock
+ @param freq_MHz desired frequency in MHz
+ @return 0-succes, other-cannot deliver desired frequency
+*/
+liblms7_status LMS7002M::SetFrequencyCGEN(const float_type freq_MHz)
+{
+ float_type dFvco;
+ float_type dFrac;
+ int16_t iHdiv;
+
+ //VCO frequency selection according to F_CLKH
+ iHdiv = (int16_t)((gCGEN_VCO_frequencies[1]/ 2) / freq_MHz) - 1;
+ dFvco = 2*(iHdiv+1) * freq_MHz;
+
+ //Integer division
+ uint16_t gINT = (uint16_t)(dFvco/mRefClkSXR_MHz - 1);
+
+ //Fractional division
+ dFrac = dFvco/mRefClkSXR_MHz - (uint32_t)(dFvco/mRefClkSXR_MHz);
+ uint32_t gFRAC = (uint32_t)(dFrac * 1048576);
+
+ Modify_SPI_Reg_bits(LMS7param(INT_SDM_CGEN), gINT); //INT_SDM_CGEN
+ Modify_SPI_Reg_bits(0x0087, 15, 0, gFRAC&0xFFFF); //INT_SDM_CGEN[15:0]
+ Modify_SPI_Reg_bits(0x0088, 3, 0, gFRAC>>16); //INT_SDM_CGEN[19:16]
+ Modify_SPI_Reg_bits(LMS7param(DIV_OUTCH_CGEN), iHdiv); //DIV_OUTCH_CGEN
+
+ return TuneVCO(VCO_CGEN);
+}
+
+/** @brief Performs VCO tuning operations for CLKGEN, SXR, SXT modules
+ @param module module selection for tuning 0-cgen, 1-SXR, 2-SXT
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::TuneVCO(VCO_Module module) // 0-cgen, 1-SXR, 2-SXT
+{
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+ int8_t i;
+ uint8_t cmphl; //comparators
+ int16_t csw_lowest = -1;
+ uint16_t addrVCOpd; // VCO power down address
+ uint16_t addrCSW_VCO;
+ uint16_t addrCMP; //comparator address
+ uint8_t lsb; //SWC lsb index
+ uint8_t msb; //SWC msb index
+
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC)); //remember used channel
+
+ if(module != VCO_CGEN) //set addresses to SX module
+ {
+ Modify_SPI_Reg_bits(LMS7param(MAC), module);
+ addrVCOpd = LMS7param(PD_VCO).address;
+ addrCSW_VCO = LMS7param(CSW_VCO).address;
+ lsb = LMS7param(CSW_VCO).lsb;
+ msb = LMS7param(CSW_VCO).msb;
+ addrCMP = LMS7param(VCO_CMPHO).address;
+ }
+ else //set addresses to CGEN module
+ {
+ addrVCOpd = LMS7param(PD_VCO_CGEN).address;
+ addrCSW_VCO = LMS7param(CSW_VCO_CGEN).address;
+ lsb = LMS7param(CSW_VCO_CGEN).lsb;
+ msb = LMS7param(CSW_VCO_CGEN).msb;
+ addrCMP = LMS7param(VCO_CMPHO_CGEN).address;
+ }
+ // Initialization
+ Modify_SPI_Reg_bits (addrVCOpd, 2, 1, 0); //activate VCO and comparator
+ if (Get_SPI_Reg_bits(addrVCOpd, 2, 1) != 0)
+ return LIBLMS7_VCO_IS_POWERED_DOWN;
+ if(module == VCO_CGEN)
+ Modify_SPI_Reg_bits(LMS7param(SPDUP_VCO_CGEN), 1); //SHORT_NOISEFIL=1 SPDUP_VCO_ Short the noise filter resistor to speed up the settling time
+ else
+ Modify_SPI_Reg_bits(LMS7param(SPDUP_VCO), 1); //SHORT_NOISEFIL=1 SPDUP_VCO_ Short the noise filter resistor to speed up the settling time
+ Modify_SPI_Reg_bits (addrCSW_VCO , msb, lsb , 0); //Set SWC_VCO<7:0>=<00000000>
+
+ i=7;
+ while(i>=0)
+ {
+ Modify_SPI_Reg_bits (addrCSW_VCO, lsb + i, lsb + i, 1); // CSW_VCO=1
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12);
+ if ( (cmphl&0x01) == 1) // reduce CSW
+ Modify_SPI_Reg_bits (addrCSW_VCO, lsb + i, lsb + i, 0); // CSW_VCO=0
+ if( cmphl == 2 && csw_lowest < 0)
+ csw_lowest = Get_SPI_Reg_bits(addrCSW_VCO, msb, lsb);
+ --i;
+ }
+ if(csw_lowest >= 0)
+ {
+ uint16_t csw_highest = Get_SPI_Reg_bits(addrCSW_VCO, msb, lsb);
+ if(csw_lowest == csw_highest)
+ {
+ while(csw_lowest>=0)
+ {
+ Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, csw_lowest);
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
+ if(Get_SPI_Reg_bits(addrCMP, 13, 12) == 0)
+ {
+ ++csw_lowest;
+ break;
+ }
+ else
+ --csw_lowest;
+ }
+ }
+ Modify_SPI_Reg_bits(addrCSW_VCO, msb, lsb, csw_lowest+(csw_highest-csw_lowest)/2);
+ }
+ if (module == VCO_CGEN)
+ Modify_SPI_Reg_bits(LMS7param(SPDUP_VCO_CGEN), 0); //SHORT_NOISEFIL=1 SPDUP_VCO_ Short the noise filter resistor to speed up the settling time
+ else
+ Modify_SPI_Reg_bits(LMS7param(SPDUP_VCO), 0); //SHORT_NOISEFIL=1 SPDUP_VCO_ Short the noise filter resistor to speed up the settling time
+ cmphl = (uint8_t)Get_SPI_Reg_bits(addrCMP, 13, 12);
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //restore previously used channel
+ if(cmphl == 2)
+ return LIBLMS7_SUCCESS;
+ else
+ return LIBLMS7_FAILURE;
+}
+
+/** @brief Returns given parameter value from chip register
+ @param param LMS7002M control parameter
+ @param fromChip read directly from chip
+ @return parameter value
+*/
+uint16_t LMS7002M::Get_SPI_Reg_bits(const LMS7Parameter ¶m, bool fromChip)
+{
+ return Get_SPI_Reg_bits(param.address, param.msb, param.lsb, fromChip);
+}
+
+/** @brief Returns given parameter value from chip register
+ @param address register address
+ @param msb most significant bit index
+ @param lsb least significant bit index
+ @param fromChip read directly from chip
+ @return register bits from selected interval, shifted to right by lsb bits
+*/
+uint16_t LMS7002M::Get_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, bool fromChip)
+{
+ return (SPI_read(address, fromChip) & (~(~0<<(msb+1)))) >> lsb; //shift bits to LSB
+}
+
+/** @brief Change given parameter value
+ @param param LMS7002M control parameter
+ @param fromChip read initial value directly from chip
+ @param value new parameter value
+*/
+liblms7_status LMS7002M::Modify_SPI_Reg_bits(const LMS7Parameter ¶m, const uint16_t value, bool fromChip)
+{
+ return Modify_SPI_Reg_bits(param.address, param.msb, param.lsb, value, fromChip);
+}
+
+/** @brief Change given parameter value
+ @param address register address
+ @param value new bits value, the value is shifted left by lsb bits
+ @param fromChip read initial value directly from chip
+*/
+liblms7_status LMS7002M::Modify_SPI_Reg_bits(const uint16_t address, const uint8_t msb, const uint8_t lsb, const uint16_t value, bool fromChip)
+{
+ uint16_t spiDataReg = SPI_read(address, fromChip); //read current SPI reg data
+ uint16_t spiMask = (~(~0 << (msb - lsb + 1))) << (lsb); // creates bit mask
+ spiDataReg = (spiDataReg & (~spiMask)) | ((value << lsb) & spiMask);//clear bits
+ return SPI_write(address, spiDataReg); //write modified data back to SPI reg
+}
+
+/** @brief Modifies given registers with values applied using masks
+ @param addr array of register addresses
+ @param masks array of applied masks
+ @param values array of values to be written
+ @param start starting index of given arrays
+ @param stop end index of given arrays
+*/
+liblms7_status LMS7002M::Modify_SPI_Reg_mask(const uint16_t *addr, const uint16_t *masks, const uint16_t *values, uint8_t start, uint8_t stop)
+{
+ liblms7_status status;
+ uint16_t reg_data;
+ vector addresses;
+ vector data;
+ while (start <= stop)
+ {
+ reg_data = SPI_read(addr[start], true, &status); //read current SPI reg data
+ reg_data &= ~masks[start];//clear bits
+ reg_data |= (values[start] & masks[start]);
+ addresses.push_back(addr[start]);
+ data.push_back(reg_data);
+ ++start;
+ }
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ SPI_write_batch(&addresses[0], &data[0], addresses.size());
+ return status;
+}
+
+/** @brief Sets SX frequency
+ @param Tx Rx/Tx module selection
+ @param freq_MHz desired frequency in MHz
+ @param refClk_MHz reference clock in MHz
+ @return 0-success, other-cannot deliver requested frequency
+*/
+liblms7_status LMS7002M::SetFrequencySX(bool tx, float_type freq_MHz, float_type refClk_MHz)
+{
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+ const uint8_t sxVCO_N = 2; //number of entries in VCO frequencies
+ const float_type m_dThrF = 5500; //threshold to enable additional divider
+ uint8_t ch; //remember used channel
+ float_type VCOfreq;
+ int8_t div_loch;
+ int8_t sel_vco;
+ bool canDeliverFrequency = false;
+ uint16_t integerPart;
+ uint32_t fractionalPart;
+ int8_t i;
+
+ //find required VCO frequency
+ for (div_loch = 6; div_loch >= 0; --div_loch)
+ {
+ VCOfreq = (1 << (div_loch + 1)) * freq_MHz;
+ if ((VCOfreq >= gVCO_frequency_table[0][0]) && (VCOfreq <= gVCO_frequency_table[2][sxVCO_N - 1]))
+ {
+ canDeliverFrequency = true;
+ break;
+ }
+ }
+ if (canDeliverFrequency == false)
+ return LIBLMS7_CANNOT_DELIVER_FREQUENCY;
+
+ integerPart = (uint16_t)(VCOfreq / (refClk_MHz * (1 + (VCOfreq > m_dThrF))) - 4);
+ fractionalPart = (uint32_t)((VCOfreq / (refClk_MHz * (1 + (VCOfreq > m_dThrF))) - (uint32_t)(VCOfreq / (refClk_MHz * (1 + (VCOfreq > m_dThrF))))) * 1048576);
+
+ ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ Modify_SPI_Reg_bits(LMS7param(MAC), tx + 1);
+ Modify_SPI_Reg_bits(LMS7param(INT_SDM), integerPart); //INT_SDM
+ Modify_SPI_Reg_bits(0x011D, 15, 0, fractionalPart & 0xFFFF); //FRAC_SDM[15:0]
+ Modify_SPI_Reg_bits(0x011E, 3, 0, (fractionalPart >> 16)); //FRAC_SDM[19:16]
+ Modify_SPI_Reg_bits(LMS7param(DIV_LOCH), div_loch); //DIV_LOCH
+ Modify_SPI_Reg_bits(LMS7param(EN_DIV2_DIVPROG), (VCOfreq > m_dThrF)); //EN_DIV2_DIVPROG
+
+ //find which VCO supports required frequency
+ Modify_SPI_Reg_bits(LMS7param(PD_VCO), 0); //
+ Modify_SPI_Reg_bits(LMS7param(PD_VCO_COMP), 0); //
+ int cswBackup = Get_SPI_Reg_bits(LMS7param(CSW_VCO)); //remember to restore previous tune value
+ canDeliverFrequency = false;
+ int tuneScore[] = { -128, -128, -128 }; //best is closest to 0
+ for (sel_vco = 0; sel_vco < 3; ++sel_vco)
+ {
+ Modify_SPI_Reg_bits(LMS7param(SEL_VCO), sel_vco);
+ liblms7_status status = TuneVCO(tx ? VCO_SXT : VCO_SXR);
+ int csw = Get_SPI_Reg_bits(LMS7param(CSW_VCO), true);
+ tuneScore[sel_vco] = -128 + csw;
+ if (status == LIBLMS7_SUCCESS)
+ canDeliverFrequency = true;
+ }
+ if (abs(tuneScore[0]) < abs(tuneScore[1]))
+ {
+ if (abs(tuneScore[0]) < abs(tuneScore[2]))
+ sel_vco = 0;
+ else
+ sel_vco = 2;
+ }
+ else
+ {
+ if (abs(tuneScore[1]) < abs(tuneScore[2]))
+ sel_vco = 1;
+ else
+ sel_vco = 2;
+ }
+ Modify_SPI_Reg_bits(LMS7param(SEL_VCO), sel_vco);
+ Modify_SPI_Reg_bits(LMS7param(CSW_VCO), cswBackup);
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //restore used channel
+ if (tx)
+ mRefClkSXT_MHz = refClk_MHz;
+ else
+ mRefClkSXR_MHz = refClk_MHz;
+ if (canDeliverFrequency == false)
+ return LIBLMS7_CANNOT_DELIVER_FREQUENCY;
+ return TuneVCO( tx ? VCO_SXT : VCO_SXR); //Rx-1, Tx-2
+}
+
+/** @brief Returns currently set SXR/SXT frequency
+ @return SX frequency MHz
+*/
+float_type LMS7002M::GetFrequencySX_MHz(bool Tx, float_type refClk_MHz)
+{
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC)); //remember previously used channel
+ float_type dMul;
+ if(Tx)
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); // Rx mac = 1, Tx max = 2
+ else
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); // Rx mac = 1, Tx max = 2
+ uint16_t gINT = Get_SPI_Reg_bits(0x011E, 13, 0); // read whole register to reduce SPI transfers
+ uint32_t gFRAC = ((gINT&0xF) * 65536) | Get_SPI_Reg_bits(0x011D, 15, 0);
+
+ dMul = (float_type)refClk_MHz / (1 << (Get_SPI_Reg_bits(LMS7param(DIV_LOCH)) + 1));
+ //Calculate real frequency according to the calculated parameters
+ dMul = dMul * ((gINT >> 4) + 4 + (float_type)gFRAC / 1048576.0) * (Get_SPI_Reg_bits(LMS7param(EN_DIV2_DIVPROG)) + 1);
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //restore used channel
+ return dMul;
+}
+
+/** @brief Loads given DC_REG values into registers
+ @param tx TxTSP or RxTSP selection
+ @param I DC_REG I value
+ @param Q DC_REG Q value
+*/
+liblms7_status LMS7002M::LoadDC_REG_IQ(bool tx, int16_t I, int16_t Q)
+{
+ if(tx)
+ {
+ Modify_SPI_Reg_bits(LMS7param(DC_REG_TXTSP), I);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_TXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_TXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_TXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(DC_REG_TXTSP), Q);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_TXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_TXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_TXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(DC_BYP_TXTSP), 0); //DC_BYP
+ }
+ else
+ {
+ Modify_SPI_Reg_bits(LMS7param(DC_REG_RXTSP), I);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_RXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_RXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDI_RXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(DC_REG_TXTSP), Q);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_RXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_RXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(TSGDCLDQ_RXTSP), 0);
+ Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 0); //DC_BYP
+ }
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Sets chosen NCO's frequency
+ @param tx transmitter or receiver selection
+ @param index NCO index from 0 to 15
+ @param freq_MHz desired NCO frequency
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SetNCOFrequency(bool tx, uint8_t index, float_type freq_MHz)
+{
+ if(index > 15)
+ return LIBLMS7_INDEX_OUT_OF_RANGE;
+ float_type refClk_MHz = GetReferenceClk_TSP_MHz(tx);
+ uint16_t addr = tx ? 0x0240 : 0x0440;
+ uint32_t fcw = (uint32_t)((freq_MHz/refClk_MHz)*4294967296);
+ SPI_write(addr+2+index*2, (fcw >> 16)); //NCO frequency control word register MSB part.
+ SPI_write(addr+3+index*2, fcw); //NCO frequency control word register LSB part.
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Returns chosen NCO's frequency in MHz
+ @param tx transmitter or receiver selection
+ @param index NCO index from 0 to 15
+ @param fromChip read frequency directly from chip or local registers
+ @return NCO frequency in MHz
+*/
+float_type LMS7002M::GetNCOFrequency_MHz(bool tx, uint8_t index, const float_type refClk_MHz, bool fromChip)
+{
+ if(index > 15)
+ return LIBLMS7_INDEX_OUT_OF_RANGE;
+ uint16_t addr = tx ? 0x0240 : 0x0440;
+ uint32_t fcw = 0;
+ fcw |= SPI_read(addr + 2 + index * 2, fromChip) << 16; //NCO frequency control word register MSB part.
+ fcw |= SPI_read(addr + 3 + index * 2, fromChip); //NCO frequency control word register LSB part.
+ return refClk_MHz*(fcw/4294967296.0);
+}
+
+/** @brief Sets chosen NCO phase offset angle when memory table MODE is 0
+@param tx transmitter or receiver selection
+@param angle_deg phase offset angle in degrees
+@return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SetNCOPhaseOffsetForMode0(bool tx, float_type angle_deg)
+{
+ uint16_t addr = tx ? 0x0241 : 0x0441;
+ uint16_t pho = (uint16_t)(65536 * (angle_deg / 360 ));
+ SPI_write(addr, pho);
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Sets chosen NCO's phase offset angle
+ @param tx transmitter or receiver selection
+ @param index PHO index from 0 to 15
+ @param angle_deg phase offset angle in degrees
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SetNCOPhaseOffset(bool tx, uint8_t index, float_type angle_deg)
+{
+ if(index > 15)
+ return LIBLMS7_INDEX_OUT_OF_RANGE;
+ uint16_t addr = tx ? 0x0244 : 0x0444;
+ uint16_t pho = (uint16_t)(65536*(angle_deg / 360));
+ SPI_write(addr+index, pho);
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Returns chosen NCO's phase offset angle in radians
+ @param tx transmitter or receiver selection
+ @param index PHO index from 0 to 15
+ @return phase offset angle in degrees
+*/
+float_type LMS7002M::GetNCOPhaseOffset_Deg(bool tx, uint8_t index)
+{
+ uint16_t addr = tx ? 0x0244 : 0x0444;
+ uint16_t pho = SPI_read(addr+index);
+ float_type angle = 360*pho/65536.0;
+ return angle;
+}
+
+/** @brief Uploads given FIR coefficients to chip
+ @param tx Transmitter or receiver selection
+ @param GFIR_index GIR index from 0 to 2
+ @param coef array of coefficients
+ @param coefCount number of coefficients
+ @return 0-success, other-failure
+
+ This function does not change GFIR*_L or GFIR*_N parameters, they have to be set manually
+*/
+liblms7_status LMS7002M::SetGFIRCoefficients(bool tx, uint8_t GFIR_index, const int16_t *coef, uint8_t coefCount)
+{
+ uint8_t index;
+ uint8_t coefLimit;
+ uint16_t startAddr;
+ if (GFIR_index == 0)
+ startAddr = 0x0280;
+ else if (GFIR_index == 1)
+ startAddr = 0x02C0;
+ else
+ startAddr = 0x0300;
+
+ if (tx == false)
+ startAddr += 0x0200;
+ if (GFIR_index < 2)
+ coefLimit = 40;
+ else
+ coefLimit = 120;
+ if (coefCount > coefLimit)
+ return LIBLMS7_TOO_MANY_VALUES;
+ vector addresses;
+ for (index = 0; index < coefCount; ++index)
+ addresses.push_back(startAddr + index + 24 * (index / 40));
+ SPI_write_batch(&addresses[0], (uint16_t*)coef, coefCount);
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Returns currently loaded FIR coefficients
+ @param tx Transmitter or receiver selection
+ @param GFIR_index GIR index from 0 to 2
+ @param coef array of returned coefficients
+ @param coefCount number of coefficients to read
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::GetGFIRCoefficients(bool tx, uint8_t GFIR_index, int16_t *coef, uint8_t coefCount)
+{
+ liblms7_status status = LIBLMS7_FAILURE;
+ uint8_t index;
+ uint8_t coefLimit;
+ uint16_t startAddr;
+ if(GFIR_index == 0)
+ startAddr = 0x0280;
+ else if (GFIR_index == 1)
+ startAddr = 0x02C0;
+ else
+ startAddr = 0x0300;
+
+ if (tx == false)
+ startAddr += 0x0200;
+ if (GFIR_index < 2)
+ coefLimit = 40;
+ else
+ coefLimit = 120;
+ if (coefCount > coefLimit)
+ return LIBLMS7_TOO_MANY_VALUES;
+
+ std::vector addresses;
+ for (index = 0; index < coefCount; ++index)
+ addresses.push_back(startAddr + index + 24 * (index / 40));
+ uint16_t spiData[120];
+ memset(spiData, 0, 120 * sizeof(uint16_t));
+ if (controlPort->IsOpen())
+ {
+ status = SPI_read_batch(&addresses[0], spiData, coefCount);
+ for (index = 0; index < coefCount; ++index)
+ coef[index] = spiData[index];
+ }
+ else
+ {
+ const int channel = Get_SPI_Reg_bits(LMS7param(MAC), false) > 1 ? 1 : 0;
+ for (index = 0; index < coefCount; ++index)
+ coef[index] = mRegistersMap->GetValue(channel, addresses[index]);
+ status = LIBLMS7_SUCCESS;
+ }
+
+ return status;
+}
+
+/** @brief Write given data value to whole register
+ @param address SPI address
+ @param data new register value
+ @return 0-succes, other-failure
+*/
+liblms7_status LMS7002M::SPI_write(uint16_t address, uint16_t data)
+{
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+
+ if ((mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003) > 1 && address >= 0x0100)
+ mRegistersMap->SetValue(1, address, data);
+ else
+ mRegistersMap->SetValue(0, address, data);
+
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_LMS7002_WR;
+ pkt.outBuffer.push_back(address >> 8);
+ pkt.outBuffer.push_back(address & 0xFF);
+ pkt.outBuffer.push_back(data >> 8);
+ pkt.outBuffer.push_back(data & 0xFF);
+ controlPort->TransferPacket(pkt);
+ if (pkt.status == STATUS_COMPLETED_CMD)
+ return LIBLMS7_SUCCESS;
+ else
+ return LIBLMS7_FAILURE;
+}
+
+/** @brief Reads whole register value from given address
+ @param address SPI address
+ @param status operation status(optional)
+ @param fromChip read value directly from chip
+ @return register value
+*/
+uint16_t LMS7002M::SPI_read(uint16_t address, bool fromChip, liblms7_status *status)
+{
+ if (controlPort == NULL)
+ {
+ if (status)
+ *status = LIBLMS7_NO_CONNECTION_MANAGER;
+ }
+ if (controlPort->IsOpen() == false || fromChip == false)
+ {
+ if ((mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003) > 1 && address >= 0x0100)
+ return mRegistersMap->GetValue(1, address);
+ else
+ return mRegistersMap->GetValue(0, address);
+ }
+
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_LMS7002_RD;
+ pkt.outBuffer.push_back(address >> 8);
+ pkt.outBuffer.push_back(address & 0xFF);
+ if (controlPort->TransferPacket(pkt) == LMScomms::TRANSFER_SUCCESS)
+ {
+ if (status)
+ *status = (pkt.status == STATUS_COMPLETED_CMD ? LIBLMS7_SUCCESS : LIBLMS7_FAILURE);
+ return (pkt.inBuffer[2] << 8) | pkt.inBuffer[3];
+ }
+ else
+ return 0;
+}
+
+/** @brief Batches multiple register writes into least ammount of transactions
+ @param spiAddr spi register addresses to be written
+ @param spiData registers data to be written
+ @param cnt number of registers to write
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt)
+{
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_LMS7002_WR;
+ uint32_t index = 0;
+ for (uint32_t i = 0; i < cnt; ++i)
+ {
+ pkt.outBuffer.push_back(spiAddr[i] >> 8);
+ pkt.outBuffer.push_back(spiAddr[i] & 0xFF);
+ pkt.outBuffer.push_back(spiData[i] >> 8);
+ pkt.outBuffer.push_back(spiData[i] & 0xFF);
+
+ if ((mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003) > 1)
+ mRegistersMap->SetValue(1, spiAddr[i], spiData[i]);
+ else
+ mRegistersMap->SetValue(0, spiAddr[i], spiData[i]);
+
+ }
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ controlPort->TransferPacket(pkt);
+ if (pkt.status == STATUS_COMPLETED_CMD)
+ return LIBLMS7_SUCCESS;
+ else
+ return LIBLMS7_FAILURE;
+}
+
+/** @brief Batches multiple register reads into least amount of transactions
+ @param spiAddr SPI addresses to read
+ @param spiData array for read data
+ @param cnt number of registers to read
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt)
+{
+ LMScomms::GenericPacket pkt;
+ pkt.cmd = CMD_LMS7002_RD;
+ uint32_t index = 0;
+ for (uint32_t i = 0; i < cnt; ++i)
+ {
+ pkt.outBuffer.push_back(spiAddr[i] >> 8);
+ pkt.outBuffer.push_back(spiAddr[i] & 0xFF);
+ }
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ LMScomms::TransferStatus status = controlPort->TransferPacket(pkt);
+ if (status != LMScomms::TRANSFER_SUCCESS)
+ return LIBLMS7_FAILURE;
+
+ for (uint32_t i = 0; i < cnt; ++i)
+ {
+ spiData[i] = (pkt.inBuffer[2*sizeof(uint16_t)*i + 2] << 8) | pkt.inBuffer[2*sizeof(uint16_t)*i + 3];
+ if ((mRegistersMap->GetValue(0, LMS7param(MAC).address) & 0x0003) > 1)
+ mRegistersMap->SetValue(1, spiAddr[i], spiData[i]);
+ else
+ mRegistersMap->SetValue(0, spiAddr[i], spiData[i]);
+ }
+ return pkt.status == STATUS_COMPLETED_CMD ? LIBLMS7_SUCCESS : LIBLMS7_FAILURE;
+ /*
+ for(int i=0; iGetValue(0, LMS7param(MAC).address) & 0x0003) > 1)
+ mRegistersMap->SetValue(1, spiAddr[i], spiData[i]);
+ else
+ mRegistersMap->SetValue(0, spiAddr[i], spiData[i]);
+ }
+ return LIBLMS7_SUCCESS;*/
+}
+
+/** @brief Performs registers test by writing known data and confirming readback data
+ @return 0-registers test passed, other-failure
+*/
+liblms7_status LMS7002M::RegistersTest()
+{
+ char chex[16];
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ liblms7_status status;
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+
+ //backup both channel data for restoration after test
+ vector ch1Addresses;
+ for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
+ for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
+ ch1Addresses.push_back(addr);
+ vector ch1Data;
+ ch1Data.resize(ch1Addresses.size(), 0);
+
+ //backup A channel
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ status = SPI_read_batch(&ch1Addresses[0], &ch1Data[0], ch1Addresses.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ vector ch2Addresses;
+ for (uint8_t i = 0; i < MEMORY_SECTIONS_COUNT; ++i)
+ for (uint16_t addr = MemorySectionAddresses[i][0]; addr <= MemorySectionAddresses[i][1]; ++addr)
+ if (addr >= 0x0100)
+ ch2Addresses.push_back(addr);
+ vector ch2Data;
+ ch2Data.resize(ch2Addresses.size(), 0);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ status = SPI_read_batch(&ch2Addresses[0], &ch2Data[0], ch2Addresses.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ //test registers
+ ResetChip();
+ Modify_SPI_Reg_bits(LMS7param(MIMO_SISO), 0);
+ Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), 0);
+ Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE2), 0);
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+
+ stringstream ss;
+
+ //check single channel memory sections
+ vector modulesToCheck = { AFE, BIAS, XBUF, CGEN, LDO, BIST, CDS, TRF, TBB, RFE, RBB, SX,
+ TxTSP, TxNCO, TxGFIR1, TxGFIR2, TxGFIR3a, TxGFIR3b, TxGFIR3c,
+ RxTSP, RxNCO, RxGFIR1, RxGFIR2, RxGFIR3a, RxGFIR3b, RxGFIR3c, LimeLight };
+ const char* moduleNames[] = { "AFE", "BIAS", "XBUF", "CGEN", "LDO", "BIST", "CDS", "TRF", "TBB", "RFE", "RBB", "SX",
+ "TxTSP", "TxNCO", "TxGFIR1", "TxGFIR2", "TxGFIR3a", "TxGFIR3b", "TxGFIR3c",
+ "RxTSP", "RxNCO", "RxGFIR1", "RxGFIR2", "RxGFIR3a", "RxGFIR3b", "RxGFIR3c", "LimeLight" };
+
+ const uint16_t patterns[] = { 0xAAAA, 0x5555 };
+ const uint8_t patternsCount = 2;
+
+ bool allTestSuccess = true;
+
+ for (unsigned i = 0; i < modulesToCheck.size(); ++i)
+ {
+ bool moduleTestsSuccess = true;
+ uint16_t startAddr = MemorySectionAddresses[modulesToCheck[i]][0];
+ uint16_t endAddr = MemorySectionAddresses[modulesToCheck[i]][1];
+ uint8_t channelCount = startAddr >= 0x0100 ? 2 : 1;
+ for (int cc = 1; cc <= channelCount; ++cc)
+ {
+ Modify_SPI_Reg_bits(LMS7param(MAC), cc);
+ sprintf(chex, "0x%04X", startAddr);
+ ss << moduleNames[i] << " [" << chex << ":";
+ sprintf(chex, "0x%04X", endAddr);
+ ss << chex << "]";
+ if (startAddr >= 0x0100)
+ ss << " Ch." << (cc == 1 ? "A" : "B");
+ ss << endl;
+ for (uint8_t p = 0; p < patternsCount; ++p)
+ moduleTestsSuccess &= RegistersTestInterval(startAddr, endAddr, patterns[p], ss) == LIBLMS7_SUCCESS;
+ }
+ allTestSuccess &= moduleTestsSuccess;
+ }
+
+ //restore register values
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ SPI_write_batch(&ch1Addresses[0], &ch1Data[0], ch1Addresses.size());
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ SPI_write_batch(&ch2Addresses[0], &ch2Data[0], ch2Addresses.size());
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+
+ fstream fout;
+ fout.open("registersTest.txt", ios::out);
+ fout << ss.str() << endl;
+ fout.close();
+
+ return allTestSuccess ? LIBLMS7_SUCCESS : LIBLMS7_FAILURE;
+}
+
+/** @brief Performs registers test for given address interval by writing given pattern data
+ @param startAddr first register address
+ @param endAddr last reigster address
+ @param pattern data to be written into registers
+ @return 0-register test passed, other-failure
+*/
+liblms7_status LMS7002M::RegistersTestInterval(uint16_t startAddr, uint16_t endAddr, uint16_t pattern, stringstream &ss)
+{
+ vector addrToWrite;
+ vector dataToWrite;
+ vector dataReceived;
+ vector dataMasks;
+
+ for (uint16_t addr = startAddr; addr <= endAddr; ++addr)
+ {
+ addrToWrite.push_back(addr);
+ }
+ dataMasks.resize(addrToWrite.size(), 0xFFFF);
+ for (uint16_t j = 0; j < sizeof(readOnlyRegisters)/sizeof(uint16_t); ++j)
+ for (uint16_t k = 0; k < addrToWrite.size(); ++k)
+ if (readOnlyRegisters[j] == addrToWrite[k])
+ {
+ dataMasks[k] = readOnlyRegistersMasks[j];
+ break;
+ }
+
+ dataToWrite.clear();
+ dataReceived.clear();
+ for (uint16_t j = 0; j < addrToWrite.size(); ++j)
+ {
+ if (addrToWrite[j] == 0x00A6)
+ dataToWrite.push_back(0x1 | pattern & ~0x2);
+ else if (addrToWrite[j] == 0x0084)
+ dataToWrite.push_back(pattern & ~0x19);
+ else
+ dataToWrite.push_back(pattern & dataMasks[j]);
+ }
+ dataReceived.resize(addrToWrite.size(), 0);
+ liblms7_status status;
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ status = SPI_read_batch(&addrToWrite[0], &dataReceived[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ bool registersMatch = true;
+ char ctemp[16];
+ for (uint16_t j = 0; j < dataToWrite.size(); ++j)
+ {
+ if (dataToWrite[j] != (dataReceived[j] & dataMasks[j]))
+ {
+ registersMatch = false;
+ sprintf(ctemp, "0x%04X", addrToWrite[j]);
+ ss << "\t" << ctemp << "(wr/rd): ";
+ sprintf(ctemp, "0x%04X", dataToWrite[j]);
+ ss << ctemp << "/";
+ sprintf(ctemp, "0x%04X", dataReceived[j]);
+ ss << ctemp << endl;
+ }
+ }
+ if (registersMatch)
+ {
+ sprintf(ctemp, "0x%04X", pattern);
+ ss << "\tRegisters OK (" << ctemp << ")\n";
+ }
+ return registersMatch ? LIBLMS7_SUCCESS : LIBLMS7_FAILURE;
+}
+
+/** @brief Parameters setup instructions for Tx calibration
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::CalibrateTxSetup(float_type bandwidth_MHz)
+{
+ //Stage 2
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ uint8_t sel_band1_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND1_TRF));
+ uint8_t sel_band2_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF));
+
+ //rfe
+ //reset RFE to defaults
+ SetDefaults(RFE);
+ if (sel_band1_trf == 1)
+ Modify_SPI_Reg_bits(LMS7param(SEL_PATH_RFE), 3); //SEL_PATH_RFE 3
+ else if (sel_band2_trf == 1)
+ Modify_SPI_Reg_bits(LMS7param(SEL_PATH_RFE), 2);
+ else
+ return LIBLMS7_BAND_NOT_SELECTED;
+
+ if (ch == 2)
+ Modify_SPI_Reg_bits(LMS7param(EN_NEXTRX_RFE), 1); // EN_NEXTTX_RFE 1
+
+ Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), 8); //G_RXLOOPB_RFE 8
+ Modify_SPI_Reg_bits(0x010C, 4, 3, 0); //PD_MXLOBUF_RFE 0, PD_QGEN_RFE 0
+ Modify_SPI_Reg_bits(LMS7param(CCOMP_TIA_RFE), 10); //CCOMP_TIA_RFE 10
+ Modify_SPI_Reg_bits(LMS7param(CFB_TIA_RFE), 2600); //CFB_TIA_RFE 2600
+ Modify_SPI_Reg_bits(LMS7param(ICT_LODC_RFE), 31); //ICT_LODC_RFE 31
+ Modify_SPI_Reg_bits(LMS7param(PD_LNA_RFE), 1);
+
+ //RBB
+ //reset RBB to defaults
+ SetDefaults(RBB);
+ Modify_SPI_Reg_bits(LMS7param(PD_LPFL_RBB), 0); //PD_LPFL_RBB 0
+ Modify_SPI_Reg_bits(LMS7param(RCC_CTL_LPFL_RBB), 0); //RCC_CTL_LPFL_RBB 0
+ Modify_SPI_Reg_bits(LMS7param(C_CTL_LPFL_RBB), 1500); //C_CTL_LPFL_RBB 1500
+ Modify_SPI_Reg_bits(LMS7param(G_PGA_RBB), 22); //G_PGA_RBB 22
+
+ //TRF
+ //reset TRF to defaults
+ //SetDefaults(TRF);
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), 0); //L_LOOPB_TXPAD_TRF 0
+ Modify_SPI_Reg_bits(LMS7param(EN_LOOPB_TXPAD_TRF), 1); //EN_LOOPB_TXPAD_TRF 1
+ Modify_SPI_Reg_bits(LMS7param(EN_G_TRF), 0); //EN_G_TRF 0
+ if (ch == 2)
+ Modify_SPI_Reg_bits(LMS7param(EN_NEXTTX_TRF), 1); //EN_NEXTTX_TRF 1
+ Modify_SPI_Reg_bits(LMS7param(LOSS_LIN_TXPAD_TRF), 0); //LOSS_LIN_TXPAD_TRF 5
+ Modify_SPI_Reg_bits(LMS7param(LOSS_MAIN_TXPAD_TRF), 0); //LOSS_MAIN_TXPAD_TRF 5
+
+ //TBB
+ //reset TBB to defaults
+ /*SetDefaults(TBB);
+ Modify_SPI_Reg_bits(LMS7param(CG_IAMP_TBB), 9); //CG_IAMP_TBB 9
+ Modify_SPI_Reg_bits(LMS7param(ICT_IAMP_FRP_TBB), 1); //ICT_IAMP_FRP_TBB 1
+ Modify_SPI_Reg_bits(LMS7param(ICT_IAMP_GG_FRP_TBB), 6); //ICT_IAMP_GG_FRP_TBB 6
+ Modify_SPI_Reg_bits(LMS7param(RCAL_LPFH_TBB), 125); //RCAL_LPFH_TBB 0
+ */
+ //AFE
+ //reset AFE to defaults
+ uint8_t isel_dac_afe =(uint8_t) Get_SPI_Reg_bits(LMS7param(ISEL_DAC_AFE));
+ SetDefaults(AFE);
+ Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), 0); //PD_RX_AFE2 0
+ Modify_SPI_Reg_bits(LMS7param(ISEL_DAC_AFE), isel_dac_afe);
+
+ if (ch == 2)
+ Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE2), 0);
+ //BIAS
+ uint16_t backup = Get_SPI_Reg_bits(LMS7param(RP_CALIB_BIAS));
+ SetDefaults(BIAS);
+ Modify_SPI_Reg_bits(LMS7param(RP_CALIB_BIAS), backup); //RP_CALIB_BIAS
+
+ //XBUF
+ Modify_SPI_Reg_bits(0x0085, 2, 0, 1); //PD_XBUF_RX 0, PD_XBUF_TX 0, EN_G_XBUF 1
+
+ //CGEN
+ //reset CGEN to defaults
+ SetDefaults(CGEN);
+ //power up VCO
+ Modify_SPI_Reg_bits(LMS7param(PD_VCO_CGEN), 0);
+
+ if (SetFrequencyCGEN(122.88) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+ if (TuneVCO(VCO_CGEN) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+
+ //SXR
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ SetDefaults(SX);
+ float_type SXTfreqMHz = GetFrequencySX_MHz(Tx, mRefClkSXT_MHz);
+
+ float_type SXRfreqMHz = SXTfreqMHz - bandwidth_MHz / 4 - 1;
+ if (SetFrequencySX(Rx, SXRfreqMHz, mRefClkSXR_MHz) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+ if (TuneVCO(VCO_SXR) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+
+ //SXT
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ Modify_SPI_Reg_bits(LMS7param(PD_LOCH_T2RBUF), 1); //PD_LOCH_T2RBUF 1
+ if (SetFrequencySX(Tx, SXTfreqMHz, mRefClkSXT_MHz) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+ if (TuneVCO(VCO_SXT) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+
+ //TXTSP
+ SetDefaults(TxTSP);
+ Modify_SPI_Reg_bits(0x0200, 3, 2, 0x3); //TSGMODE 1, INSEL 1
+ Modify_SPI_Reg_bits(0x0208, 6, 4, 0x7); //GFIR3_BYP 1, GFIR2_BYP 1, GFIR1_BYP 1
+ LoadDC_REG_IQ(Tx, (int16_t)0x7FFF, (int16_t)0x8000);
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ Modify_SPI_Reg_bits(0x0440, 4, 0, 0); //TX SEL[3:0] = 0 & MODE = 0
+
+ float_type offset = 0.2;
+ if (bandwidth_MHz == 8)
+ {
+ //SXR
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ SetDefaults(SX);
+ float_type SXTfreqMHz = GetFrequencySX_MHz(Tx, mRefClkSXT_MHz);
+
+ float_type sxrFreq = SXTfreqMHz - bandwidth_MHz / 4 - 1 - offset;
+ if (SetFrequencySX(Rx, sxrFreq, mRefClkSXR_MHz) != LIBLMS7_SUCCESS)
+ return LIBLMS7_FAILURE;
+ SetNCOFrequency(Tx, 0, bandwidth_MHz / 4 + offset);
+ }
+ else
+ SetNCOFrequency(Tx, 0, bandwidth_MHz / 4);
+
+ //RXTSP
+ SetDefaults(RxTSP);
+ Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 1); //AGC_MODE 1
+ Modify_SPI_Reg_bits(0x040C, 7, 0, 0xBF);
+ Modify_SPI_Reg_bits(LMS7param(CAPSEL), 0);
+ Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 0); //Decimation HBD ratio
+ Modify_SPI_Reg_bits(LMS7param(AGC_AVG_RXTSP), 0x7); //agc_avg iq corr
+
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Flips the CAPTURE bit and returns digital RSSI value
+*/
+uint32_t LMS7002M::GetRSSI()
+{
+ Modify_SPI_Reg_bits(LMS7param(CAPTURE), 0);
+ Modify_SPI_Reg_bits(LMS7param(CAPTURE), 1);
+ return (Get_SPI_Reg_bits(0x040F, 15, 0) << 2) | Get_SPI_Reg_bits(0x040E, 1, 0);
+}
+
+/** @brief Sets Rx Dc offsets by converting two's complementary numbers to sign and magnitude
+*/
+void LMS7002M::SetRxDCOFF(int8_t offsetI, int8_t offsetQ)
+{
+ uint16_t valToSend = 0;
+ if (offsetI < 0)
+ valToSend |= 0x40;
+ valToSend |= labs(offsetI);
+ valToSend = valToSend << 7;
+ if (offsetQ < 0)
+ valToSend |= 0x40;
+ valToSend |= labs(offsetQ);
+ SPI_write(0x010E, valToSend);
+}
+
+/** @brief Calibrates Transmitter. DC correction, IQ gains, IQ phase correction
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::CalibrateTx(float_type bandwidth_MHz)
+{
+ liblms7_status status;
+ Log("Tx calibration started", LOG_INFO);
+ BackupAllRegisters();
+
+ int16_t iqcorr = 0;
+ uint16_t gcorrq = 0;
+ uint16_t gcorri = 0;
+ uint16_t dccorri;
+ uint16_t dccorrq;
+ int16_t corrI = 0;
+ int16_t corrQ = 0;
+ uint32_t minRSSI_i;
+ uint32_t minRSSI_q;
+ uint32_t minRSSI_iq;
+ int16_t i;
+ int16_t offsetI = 0;
+ int16_t offsetQ = 0;
+
+ const short firCoefs[] =
+ {
+ -2531,
+ -517,
+ 2708,
+ 188,
+ -3059,
+ 216,
+ 3569,
+ -770,
+ -4199,
+ 1541,
+ 4886,
+ -2577,
+ -5552,
+ 3909,
+ 6108,
+ -5537,
+ -6457,
+ 7440,
+ 6507,
+ -9566,
+ -6174,
+ 11845,
+ 5391,
+ -14179,
+ -4110,
+ 16457,
+ 2310,
+ -18561,
+ 0,
+ 20369,
+ -2780,
+ -21752,
+ 5963,
+ 22610,
+ -9456,
+ -22859,
+ 13127,
+ 22444,
+ -16854,
+ -21319,
+ 20489,
+ 19492,
+ -23883,
+ -17002,
+ 26881,
+ 13902,
+ -29372,
+ -10313,
+ 31226,
+ 6345,
+ -32380,
+ -2141,
+ 32767,
+ -2141,
+ -32380,
+ 6345,
+ 31226,
+ -10313,
+ -29372,
+ 13902,
+ 26881,
+ -17002,
+ -23883,
+ 19492,
+ 20489,
+ -21319,
+ -16854,
+ 22444,
+ 13127,
+ -22859,
+ -9456,
+ 22610,
+ 5963,
+ -21752,
+ -2780,
+ 20369,
+ 0,
+ -18561,
+ 2310,
+ 16457,
+ -4110,
+ -14179,
+ 5391,
+ 11845,
+ -6174,
+ -9566,
+ 6507,
+ 7440,
+ -6457,
+ -5537,
+ 6108,
+ 3909,
+ -5552,
+ -2577,
+ 4886,
+ 1541,
+ -4199,
+ -770,
+ 3569,
+ 216,
+ -3059,
+ 188,
+ 2708,
+ -517,
+ -2531
+ };
+
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ //Stage 1
+ uint8_t sel_band1_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND1_TRF));
+ uint8_t sel_band2_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF));
+ Log("Setup stage", LOG_INFO);
+ status = CalibrateTxSetup(bandwidth_MHz);
+ if (status != LIBLMS7_SUCCESS)
+ goto TxCalibrationEnd; //go to ending stage to restore registers
+
+ //Stage 3
+ //Calibrate Rx DC
+ Log("Rx DC calibration", LOG_INFO);
+ {
+ uint16_t requiredRegs[] = { 0x0400, 0x040A, 0x010D, 0x040C };
+ uint16_t requiredMask[] = { 0x6000, 0x3007, 0x0040, 0x00FF }; //CAPSEL, AGC_MODE, AGC_AVG, EN_DCOFF, Bypasses
+ uint16_t requiredValue[] = { 0x0000, 0x1007, 0x0040, 0x00BD };
+
+ Modify_SPI_Reg_mask(requiredRegs, requiredMask, requiredValue, 0, 3);
+ }
+
+ for (i = 0; i<6; ++i)
+ {
+ FindMinRSSI(LMS7param(DCOFFI_RFE), offsetI, &offsetI, 3, 2, 32 >> i);
+ FindMinRSSI(LMS7param(DCOFFQ_RFE), offsetQ, &offsetQ, 3, 2, 32 >> i);
+ }
+ SetRxDCOFF((int8_t)offsetI, (int8_t)offsetQ);
+ Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 0); // DC_BYP 0
+
+ sel_band1_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND1_TRF));
+ sel_band2_trf = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF));
+ //B
+ Modify_SPI_Reg_bits(0x0100, 0, 0, 1); //EN_G_TRF 1
+ if (sel_band1_trf == 1)
+ {
+ Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_1_RFE), 0); //PD_RLOOPB_1_RFE 0
+ Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB1_RFE), 0); //EN_INSHSW_LB1 0
+ }
+ if (sel_band2_trf == 1)
+ {
+ Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_2_RFE), 0); //PD_RLOOPB_2_RFE 0
+ Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB2_RFE), 0); // EN_INSHSW_LB2 0
+ }
+ FixRXSaturation();
+
+ Modify_SPI_Reg_bits(LMS7param(GFIR3_BYP_RXTSP), 0); //GFIR3_BYP 0
+ Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 2);
+ Modify_SPI_Reg_bits(LMS7param(GFIR3_L_RXTSP), 7);
+ Modify_SPI_Reg_bits(LMS7param(GFIR3_N_RXTSP), 7);
+
+ SetGFIRCoefficients(Rx, 2, firCoefs, sizeof(firCoefs) / sizeof(int16_t));
+
+ Log("IQ correction stage", LOG_INFO);
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_TXTSP), 2047);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_TXTSP), 2047);
+
+ Modify_SPI_Reg_bits(LMS7param(IQCORR_TXTSP), 0);
+
+ Log("I gain", LOG_INFO);
+ minRSSI_i = FindMinRSSI_Gain(LMS7param(GCORRI_TXTSP), &gcorri);
+
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_TXTSP), 2047);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_TXTSP), 2047);
+
+ Log("Q gain", LOG_INFO);
+ minRSSI_q = FindMinRSSI_Gain(LMS7param(GCORRQ_TXTSP), &gcorrq);
+
+ if (minRSSI_i < minRSSI_q)
+ gcorrq = 2047;
+ else
+ gcorri = 2047;
+
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_TXTSP), gcorri);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_TXTSP), gcorrq);
+
+ Log("Phase", LOG_INFO);
+ iqcorr = 0;
+ for (uint8_t i = 0; i<9; ++i)
+ minRSSI_iq = FindMinRSSI(LMS7param(IQCORR_TXTSP), iqcorr, &iqcorr, 3, 1, 256 >> i);
+
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_TXTSP), gcorri);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_TXTSP), gcorrq);
+ Modify_SPI_Reg_bits(LMS7param(IQCORR_TXTSP), iqcorr);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ status = SetFrequencySX(Rx, GetFrequencySX_MHz(Tx, mRefClkSXT_MHz)-1, mRefClkSXR_MHz);
+ if (status != LIBLMS7_SUCCESS)
+ goto TxCalibrationEnd; //go to ending stage to restore registers
+
+ //C
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(CAPSEL), 0);
+
+ Log("TX LO calibration", LOG_INFO);
+
+ //Calibrate Tx DC
+ for (uint8_t i = 0; i<7; ++i)
+ {
+ FindMinRSSI(LMS7param(DCCORRI_TXTSP), corrI, &corrI, 3, 1, 64 >> i);
+ FindMinRSSI(LMS7param(DCCORRQ_TXTSP), corrQ, &corrQ, 3, 1, 64 >> i);
+ }
+
+ dccorri = Get_SPI_Reg_bits(LMS7param(DCCORRI_TXTSP));
+ dccorrq = Get_SPI_Reg_bits(LMS7param(DCCORRQ_TXTSP));
+
+ // Stage 4
+TxCalibrationEnd:
+ Log("Restoring registers state", LOG_INFO);
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ RestoreAllRegisters();
+ if (status != LIBLMS7_SUCCESS)
+ {
+ Log("Tx calibration failed", LOG_WARNING);
+ return status;
+ }
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ Modify_SPI_Reg_bits(LMS7param(DCCORRI_TXTSP), dccorri);
+ Modify_SPI_Reg_bits(LMS7param(DCCORRQ_TXTSP), dccorrq);
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_TXTSP), gcorri);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_TXTSP), gcorrq);
+ Modify_SPI_Reg_bits(LMS7param(IQCORR_TXTSP), iqcorr);
+
+ Modify_SPI_Reg_bits(LMS7param(DC_BYP_TXTSP), 0); //DC_BYP
+ Modify_SPI_Reg_bits(0x0208, 1, 0, 0); //GC_BYP PH_BYP
+ Log("Tx calibration finished", LOG_INFO);
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Performs Rx DC offsets calibration
+*/
+void LMS7002M::CalibrateRxDC_RSSI()
+{
+ int16_t i;
+ int16_t offsetI = 0;
+ int16_t offsetQ = 0;
+ uint16_t requiredRegs[] = { 0x0400, 0x040A, 0x010D, 0x040C };
+ uint16_t requiredMask[] = { 0x6000, 0x3007, 0x0040, 0x00FF }; //CAPSEL, AGC_MODE, AGC_AVG, EN_DCOFF, Bypasses
+ uint16_t requiredValue[] = { 0x0000, 0x1007, 0x0040, 0x00BD };
+
+ Modify_SPI_Reg_mask(requiredRegs, requiredMask, requiredValue, 0, 3);
+ for (i = 0; i<6; ++i)
+ {
+ FindMinRSSI(LMS7param(DCOFFI_RFE), offsetI, &offsetI, 3, 2, 32 >> i);
+ FindMinRSSI(LMS7param(DCOFFQ_RFE), offsetQ, &offsetQ, 3, 2, 32 >> i);
+ }
+ Modify_SPI_Reg_bits(LMS7param(EN_DCOFF_RXFE_RFE), 1);
+ SetRxDCOFF((int8_t)offsetI, (int8_t)offsetQ);
+ Modify_SPI_Reg_bits(LMS7param(DC_BYP_RXTSP), 0); // DC_BYP 0
+}
+
+/** @brief Tries to detect and fix gains if Rx is saturated
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::FixRXSaturation()
+{
+ uint8_t g_rxloopb = 0;
+ Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), g_rxloopb);
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), 3);
+
+ int8_t lLoopb = 3;
+ const uint32_t rssi_saturation_level = 0xD000;
+ while (g_rxloopb < 15)
+ {
+ g_rxloopb += 1;
+ Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), g_rxloopb);
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), 3);
+ if (GetRSSI() < rssi_saturation_level)
+ {
+ for (lLoopb = 3; lLoopb >= 0; --lLoopb)
+ {
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), lLoopb);
+ if (GetRSSI() > rssi_saturation_level)
+ {
+ ++lLoopb;
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), lLoopb);
+ goto finished;
+ }
+ }
+ }
+ else
+ {
+ g_rxloopb -= 1;
+ Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), g_rxloopb);
+ break;
+ }
+ }
+finished:
+ return GetRSSI() < rssi_saturation_level ? LIBLMS7_SUCCESS : LIBLMS7_FAILURE;
+}
+
+uint32_t LMS7002M::FindMinRSSI(const LMS7Parameter ¶m, const int16_t startValue, int16_t *result, const uint8_t scanWidth, const uint8_t twoCompl, int8_t stepMult)
+{
+ return FindMinRSSI(param.address, param.msb, param.lsb, startValue, result, scanWidth, twoCompl, stepMult);
+}
+
+/** @brief Searches for minimal RSSI value while changing given address bits
+@param addr address of parameter being changed
+@param msb most significant bit index
+@param lsb least significant bit index
+@param startValue initial value where to start search
+@param result found minimal parameter value will be set here
+@param twoCompl varying parameter value is treated as two's complement
+@return found minimal RSSI value
+*/
+uint32_t LMS7002M::FindMinRSSI(const uint16_t addr, const uint8_t msb, const uint8_t lsb, const int16_t startValue, int16_t *result, const uint8_t scanWidth, const uint8_t twoCompl, int8_t stepMult)
+{
+ if (scanWidth < 1)
+ return ~0;
+ int minI;
+ int min = startValue;
+ int globMin = 0;
+ uint32_t minRSSI = ~0;
+ unsigned int *rssiField = new unsigned int[scanWidth];
+ int minRSSIindex;
+ int i;
+ int maxVal;
+ int minVal = 0;
+ if (twoCompl)
+ {
+ maxVal = (~(~0x0 << (msb - lsb + 1))) / 2;
+ minVal = -(~(~0x0 << (msb - lsb + 1))) / 2 - 1;
+ }
+ else
+ maxVal = (~(~0x0 << (msb - lsb + 1)));
+
+ Modify_SPI_Reg_bits(addr, msb, lsb, startValue);
+
+ Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 1);
+ Modify_SPI_Reg_bits(LMS7param(CAPSEL), 0);
+
+ minRSSIindex = 0;
+ for (i = 0; i maxVal)
+ currentValue = maxVal;
+ if (twoCompl == 2)
+ {
+ uint16_t valToSend = 0;
+ if (currentValue < 0)
+ valToSend |= 0x40;
+ valToSend |= labs(currentValue);
+ Modify_SPI_Reg_bits(addr, msb, lsb, valToSend);
+ }
+ else
+ Modify_SPI_Reg_bits(addr, msb, lsb, currentValue);
+
+ rssiField[i] = GetRSSI();
+ }
+ minI = min;
+ minRSSIindex = 0;
+ for (i = 0; i maxVal)
+ minI = maxVal;
+ else if (minI < minVal)
+ minI = minVal;
+ globMin = minI;
+ }
+ min = minI;
+
+ Modify_SPI_Reg_bits(addr, msb, lsb, min);
+
+ *result = min;
+ return minRSSI;
+}
+
+/** @brief Sets given module registers to default values
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::SetDefaults(MemorySection module)
+{
+ liblms7_status status = LIBLMS7_SUCCESS;
+ vector addrs;
+ vector values;
+ for(uint32_t address = MemorySectionAddresses[module][0]; address <= MemorySectionAddresses[module][1]; ++address)
+ {
+ addrs.push_back(address);
+ values.push_back(mRegistersMap->GetDefaultValue(address));
+ }
+ status = SPI_write_batch(&addrs[0], &values[0], addrs.size());
+ return status;
+}
+
+/** @brief Parameters setup instructions for Rx calibration
+ @param bandwidth_MHz filter bandwidth in MHz
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::CalibrateRxSetup(float_type bandwidth_MHz)
+{
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+
+ //rfe
+ if (ch == 2)
+ Modify_SPI_Reg_bits(LMS7param(EN_NEXTTX_TRF), 1); // EN_NEXTTX_TRF 0
+
+ Modify_SPI_Reg_bits(LMS7param(G_RXLOOPB_RFE), 15); //G_RXLOOPB_RFE 15
+ Modify_SPI_Reg_bits(0x010C, 4, 3, 0); //PD_MXLOBUF_RFE 0, PD_QGEN_RFE 0
+ Modify_SPI_Reg_bits(0x010C, 1, 1, 0); //PD_TIA 0
+ Modify_SPI_Reg_bits(0x010C, 7, 7, 1); //PD_LNA 1
+
+ Modify_SPI_Reg_bits(0x0110, 4, 0, 31); //ICT_LO_RFE 31
+ Modify_SPI_Reg_bits(0x010D, 4, 1, 0xFF); // all short switches are enabled
+
+ //RBB
+ Modify_SPI_Reg_bits(0x0115, 15, 14, 0); //Loopback switches disable
+ Modify_SPI_Reg_bits(0x0119, 15, 15, 0); //OSW_PGA 0
+
+ //TRF
+ //reset TRF to defaults
+ SetDefaults(TRF);
+ Modify_SPI_Reg_bits(LMS7param(L_LOOPB_TXPAD_TRF), 0); //L_LOOPB_TXPAD_TRF 0
+ Modify_SPI_Reg_bits(LMS7param(EN_LOOPB_TXPAD_TRF), 1); //EN_LOOPB_TXPAD_TRF 1
+ Modify_SPI_Reg_bits(LMS7param(EN_G_TRF), 0); //EN_G_TRF 0
+ if (ch == 2)
+ Modify_SPI_Reg_bits(LMS7param(EN_NEXTTX_TRF), 1); //EN_NEXTTX_TRF 1
+ Modify_SPI_Reg_bits(LMS7param(LOSS_LIN_TXPAD_TRF), 0); //LOSS_LIN_TXPAD_TRF 5
+ Modify_SPI_Reg_bits(LMS7param(LOSS_MAIN_TXPAD_TRF), 0); //LOSS_MAIN_TXPAD_TRF 5
+
+ //TBB
+ //reset TBB to defaults
+ SetDefaults(TBB);
+ Modify_SPI_Reg_bits(LMS7param(CG_IAMP_TBB), 9); //CG_IAMP_TBB 9
+ Modify_SPI_Reg_bits(LMS7param(ICT_IAMP_FRP_TBB), 1); //ICT_IAMP_FRP_TBB 1
+ Modify_SPI_Reg_bits(LMS7param(ICT_IAMP_GG_FRP_TBB), 6); //ICT_IAMP_GG_FRP_TBB 6
+
+ //AFE
+ //reset AFE to defaults
+ SetDefaults(AFE);
+ Modify_SPI_Reg_bits(LMS7param(PD_RX_AFE2), 0); //PD_RX_AFE2
+ if (ch == 2)
+ {
+ Modify_SPI_Reg_bits(LMS7param(PD_TX_AFE2), 0); //PD_TX_AFE2
+ }
+ //BIAS
+ uint16_t backup = Get_SPI_Reg_bits(0x0084, 10, 6);
+ SetDefaults(BIAS);
+ Modify_SPI_Reg_bits(0x0084, 10, 6, backup); //RP_CALIB_BIAS
+
+ //XBUF
+ Modify_SPI_Reg_bits(0x0085, 2, 0, 1); //PD_XBUF_RX 0, PD_XBUF_TX 0, EN_G_XBUF 1
+
+ //CGEN
+ //reset CGEN to defaults
+ SetDefaults(CGEN);
+ //power up VCO
+ Modify_SPI_Reg_bits(0x0086, 2, 2, 0);
+
+ liblms7_status status = SetFrequencyCGEN(122.88);
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ // //SXR
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ float_type SXRfreqMHz = GetFrequencySX_MHz(Rx, mRefClkSXR_MHz);
+
+ //SXT
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ Modify_SPI_Reg_bits(LMS7param(PD_LOCH_T2RBUF), 1); //PD_LOCH_t2RBUF 1
+ status = SetFrequencySX(Tx, SXRfreqMHz + bandwidth_MHz / 4, mRefClkSXT_MHz);
+ if ( status != LIBLMS7_SUCCESS)
+ return status;
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+
+ //TXTSP
+ SetDefaults(TxTSP);
+ Modify_SPI_Reg_bits(0x0200, 3, 2, 0x3); //TSGMODE 1, INSEL 1
+ //Modify_SPI_Reg_bits(0x0208, 6, 4, 0xFFFF); //GFIR3_BYP 1, GFIR2_BYP 1, GFIR1_BYP 1
+ Modify_SPI_Reg_bits(0x0208, 6, 6, 1); //GFIR3_BYP 1, GFIR2_BYP 1, GFIR1_BYP 1
+ Modify_SPI_Reg_bits(0x0208, 5, 5, 1); //GFIR3_BYP 1, GFIR2_BYP 1, GFIR1_BYP 1
+ Modify_SPI_Reg_bits(0x0208, 4, 4, 1); //GFIR3_BYP 1, GFIR2_BYP 1, GFIR1_BYP 1
+ LoadDC_REG_IQ(Tx, (int16_t)0x7FFF, (int16_t)0x8000);
+ SetNCOFrequency(Tx, 0, 0);
+
+ //RXTSP
+ SetDefaults(RxTSP);
+ Modify_SPI_Reg_bits(LMS7param(AGC_MODE_RXTSP), 1); //AGC_MODE 1
+ Modify_SPI_Reg_bits(0x040C, 7, 7, 0x1); //CMIX_BYP 1
+ Modify_SPI_Reg_bits(0x040C, 6, 6, 0x0); //AGC_BYP 0
+ Modify_SPI_Reg_bits(0x040C, 5, 5, 1); //
+ Modify_SPI_Reg_bits(0x040C, 4, 4, 1); //
+ Modify_SPI_Reg_bits(0x040C, 3, 3, 1); //
+ Modify_SPI_Reg_bits(0x040C, 2, 2, 1); // DC_BYP
+ Modify_SPI_Reg_bits(0x040C, 1, 1, 1); //
+ Modify_SPI_Reg_bits(0x040C, 0, 0, 1); //
+
+ Modify_SPI_Reg_bits(LMS7param(CAPSEL), 0);
+ Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 2);
+ Modify_SPI_Reg_bits(LMS7param(AGC_AVG_RXTSP), 0x7); //agc_avg iq corr
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Calibrates Receiver. DC offset, IQ gains, IQ phase correction
+ @return 0-success, other-failure
+*/
+liblms7_status LMS7002M::CalibrateRx(float_type bandwidth_MHz)
+{
+ liblms7_status status;
+ uint32_t minRSSI_i;
+ uint32_t minRSSI_q;
+ int16_t iqcorr_rx = 0;
+ uint32_t minRSSI_iq;
+ int16_t dcoffi;
+ int16_t dcoffq;
+
+ const int16_t firCoefs[] =
+ {
+ -2531,
+ -517,
+ 2708,
+ 188,
+ -3059,
+ 216,
+ 3569,
+ -770,
+ -4199,
+ 1541,
+ 4886,
+ -2577,
+ -5552,
+ 3909,
+ 6108,
+ -5537,
+ -6457,
+ 7440,
+ 6507,
+ -9566,
+ -6174,
+ 11845,
+ 5391,
+ -14179,
+ -4110,
+ 16457,
+ 2310,
+ -18561,
+ 0,
+ 20369,
+ -2780,
+ -21752,
+ 5963,
+ 22610,
+ -9456,
+ -22859,
+ 13127,
+ 22444,
+ -16854,
+ -21319,
+ 20489,
+ 19492,
+ -23883,
+ -17002,
+ 26881,
+ 13902,
+ -29372,
+ -10313,
+ 31226,
+ 6345,
+ -32380,
+ -2141,
+ 32767,
+ -2141,
+ -32380,
+ 6345,
+ 31226,
+ -10313,
+ -29372,
+ 13902,
+ 26881,
+ -17002,
+ -23883,
+ 19492,
+ 20489,
+ -21319,
+ -16854,
+ 22444,
+ 13127,
+ -22859,
+ -9456,
+ 22610,
+ 5963,
+ -21752,
+ -2780,
+ 20369,
+ 0,
+ -18561,
+ 2310,
+ 16457,
+ -4110,
+ -14179,
+ 5391,
+ 11845,
+ -6174,
+ -9566,
+ 6507,
+ 7440,
+ -6457,
+ -5537,
+ 6108,
+ 3909,
+ -5552,
+ -2577,
+ 4886,
+ 1541,
+ -4199,
+ -770,
+ 3569,
+ 216,
+ -3059,
+ 188,
+ 2708,
+ -517,
+ -2531
+ };
+
+ Log("Rx calibration started", LOG_INFO);
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ Log("Saving registers state", LOG_INFO);
+ BackupAllRegisters();
+ uint8_t sel_path_rfe = (uint8_t)Get_SPI_Reg_bits(LMS7param(SEL_PATH_RFE));
+ if (sel_path_rfe == 1 || sel_path_rfe == 0)
+ return LIBLMS7_BAD_SEL_PATH;
+
+ Log("Setup stage", LOG_INFO);
+ status = CalibrateRxSetup(bandwidth_MHz);
+ if (status != LIBLMS7_SUCCESS)
+ goto RxCalibrationEndStage;
+
+ Log("Rx DC calibration", LOG_INFO);
+ CalibrateRxDC_RSSI();
+ dcoffi = Get_SPI_Reg_bits(LMS7param(DCOFFI_RFE));
+ dcoffq = Get_SPI_Reg_bits(LMS7param(DCOFFQ_RFE));
+ Modify_SPI_Reg_bits(LMS7param(EN_G_TRF), 1);
+
+ if (sel_path_rfe == 2)
+ {
+ Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_2_RFE), 0);
+ Modify_SPI_Reg_bits(0x0103, 10, 10, 1);
+ Modify_SPI_Reg_bits(0x0103, 11, 11, 0);
+ Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB2_RFE), 0);
+ }
+ if (sel_path_rfe == 3)
+ {
+ Modify_SPI_Reg_bits(LMS7param(PD_RLOOPB_1_RFE), 0);
+ Modify_SPI_Reg_bits(0x0103, 11, 11, 1);
+ Modify_SPI_Reg_bits(0x0103, 10, 10, 0);
+ Modify_SPI_Reg_bits(LMS7param(EN_INSHSW_LB1_RFE), 0);
+ }
+
+ Modify_SPI_Reg_bits(0x040C, 7, 7, 0); //CMIX_BYP 0
+ Modify_SPI_Reg_bits(0x040C, 2, 0, 0); //DC_BYP 0, GC_BYP 0, PH_BYP 0
+ Modify_SPI_Reg_bits(LMS7param(CMIX_GAIN_RXTSP), 1); //CMIX_GAIN 1 +6 db
+ Modify_SPI_Reg_bits(0x040C, 13, 13, 1); //CMIX_SC 1
+
+ FixRXSaturation();
+
+ Modify_SPI_Reg_bits(0x040C, 5, 5, 0); //GFIR3_BYP 0
+ Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), 2);
+ Modify_SPI_Reg_bits(LMS7param(GFIR3_L_RXTSP), 7);
+ Modify_SPI_Reg_bits(LMS7param(GFIR3_N_RXTSP), 7);
+
+ SetGFIRCoefficients(Rx, 2, firCoefs, sizeof(firCoefs) / sizeof(int16_t));
+
+ SetNCOFrequency(Rx, 0, bandwidth_MHz / 4 + 1);
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_RXTSP), 2047);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_RXTSP), 2047);
+
+ Log("IQ correction stage", LOG_INFO);
+ iqcorr_rx = 0;
+ for (int i = 0; i<9; ++i)
+ minRSSI_iq = FindMinRSSI(LMS7param(IQCORR_RXTSP), iqcorr_rx, &iqcorr_rx, 3, 1, 256 >> i);
+ Modify_SPI_Reg_bits(LMS7param(IQCORR_RXTSP), iqcorr_rx);
+
+ uint16_t mingcorri;
+ Log("I gain", LOG_INFO);
+ minRSSI_i = FindMinRSSI_Gain(LMS7param(GCORRI_RXTSP), &mingcorri);
+
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_RXTSP), 2047);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_RXTSP), 2047);
+
+ Log("Q gain", LOG_INFO);
+ uint16_t mingcorrq;
+ minRSSI_q = FindMinRSSI_Gain(LMS7param(GCORRQ_RXTSP), &mingcorrq);
+
+ if (minRSSI_i < minRSSI_q)
+ mingcorrq = 2047;
+ else
+ mingcorri = 2047;
+
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_RXTSP), mingcorri);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_RXTSP), mingcorrq);
+
+ Log("Phase", LOG_INFO);
+ for (int i = 0; i<9; ++i)
+ minRSSI_iq = FindMinRSSI(LMS7param(IQCORR_RXTSP), iqcorr_rx, &iqcorr_rx, 3, 1, 256 >> i);
+
+RxCalibrationEndStage:
+ Log("Restoring registers state", LOG_INFO);
+ RestoreAllRegisters();
+ if (status != LIBLMS7_SUCCESS)
+ {
+ Log("Rx calibration failed", LOG_WARNING);
+ return status;
+ }
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+ SetRxDCOFF((int8_t)dcoffi, (int8_t)dcoffq);
+ Modify_SPI_Reg_bits(LMS7param(EN_DCOFF_RXFE_RFE), 1);
+ Modify_SPI_Reg_bits(LMS7param(GCORRI_RXTSP), mingcorri);
+ Modify_SPI_Reg_bits(LMS7param(GCORRQ_RXTSP), mingcorrq);
+ Modify_SPI_Reg_bits(LMS7param(IQCORR_RXTSP), iqcorr_rx);
+ Modify_SPI_Reg_bits(0x040C, 2, 0, 0); //DC_BYP 0, GC_BYP 0, PH_BYP 0
+ Modify_SPI_Reg_bits(0x0110, 4, 0, 31); //ICT_LO_RFE 31
+ Log("Rx calibration finished", LOG_INFO);
+ return LIBLMS7_SUCCESS;
+}
+
+const uint16_t backupAddrs[] = {
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+ 0x0029, 0x002A, 0x002B, 0x002C, 0x002E, 0x0081, 0x0082, 0x0084, 0x0085,
+ 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0092, 0x0093, 0x0094,
+ 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E,
+ 0x009F, 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8,
+ 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0100, 0x0101, 0x0102, 0x0103,
+ 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010C, 0x010D, 0x010E,
+ 0x010F, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118,
+ 0x0119, 0x011A, 0x011C, 0x011D, 0x011E, 0x011F, 0x0120, 0x0121, 0x0122, 0x0123,
+ 0x0124, 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208,
+ 0x0240, 0x0242, 0x0243, 0x0400, 0x0401, 0x0402,
+ 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A, 0x040B, 0x040C,
+ 0x0440, 0x0442, 0x0443 };
+uint16_t backupRegs[sizeof(backupAddrs) / 2];
+const uint16_t backupSXAddr[] = { 0x011C, 0x011D, 0x011E, 0x011F, 0x01200, 0x0121, 0x0122, 0x0123, 0x0124 };
+uint16_t backupRegsSXR[sizeof(backupSXAddr) / 2];
+uint16_t backupRegsSXT[sizeof(backupSXAddr) / 2];
+
+/** @brief Stores chip current registers state into memory for later restoration
+*/
+void LMS7002M::BackupAllRegisters()
+{
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ SPI_read_batch(backupAddrs, backupRegs, sizeof(backupAddrs) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); // channel A
+ SPI_read_batch(backupSXAddr, backupRegsSXR, sizeof(backupRegsSXR) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); // channel B
+ SPI_read_batch(backupSXAddr, backupRegsSXT, sizeof(backupRegsSXR) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+}
+
+/** @brief Sets chip registers to state that was stored in memory using BackupAllRegisters()
+*/
+void LMS7002M::RestoreAllRegisters()
+{
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+ SPI_write_batch(backupAddrs, backupRegs, sizeof(backupAddrs) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); // channel A
+ SPI_write_batch(backupSXAddr, backupRegsSXR, sizeof(backupRegsSXR) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); // channel B
+ SPI_write_batch(backupSXAddr, backupRegsSXT, sizeof(backupRegsSXR) / sizeof(uint16_t));
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch);
+}
+
+/** @brief Searches for minimal digital RSSI value by changing given gain parameter
+ @param param LMS7002M gain correction parameter
+ @param foundValue returns value which achieved minimal RSSI
+ @return minimal found RSSI value
+*/
+uint32_t LMS7002M::FindMinRSSI_Gain(const LMS7Parameter ¶m, uint16_t *foundValue)
+{
+ uint32_t RSSI = ~0 - 2;
+ uint32_t prevRSSI = RSSI + 1;
+ uint8_t decrement = 2;
+ uint16_t gcorr = 2047;
+ while (gcorr > 1024)
+ {
+ Modify_SPI_Reg_bits(param, gcorr);
+ RSSI = GetRSSI();
+ if (RSSI < prevRSSI)
+ {
+ prevRSSI = RSSI;
+ *foundValue = gcorr;
+ gcorr -= decrement;
+ decrement *= 2;
+ }
+ else
+ {
+ if (decrement == 2)
+ break;
+ gcorr -= decrement;
+ decrement = 2;
+ }
+ }
+ return prevRSSI;
+}
+
+/** @brief Reads all chip configuration and checks if it matches with local registers copy
+*/
+bool LMS7002M::IsSynced()
+{
+ if (controlPort->IsOpen() == false)
+ return false;
+ bool isSynced = true;
+ liblms7_status status;
+
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC));
+
+ vector addrToRead = mRegistersMap->GetUsedAddresses(0);
+ vector dataReceived;
+ dataReceived.resize(addrToRead.size(), 0);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size());
+ if (status != LIBLMS7_SUCCESS)
+ {
+ isSynced = false;
+ goto isSyncedEnding;
+ }
+
+ //mask out readonly bits
+ for (uint16_t j = 0; j < sizeof(readOnlyRegisters) / sizeof(uint16_t); ++j)
+ for (uint16_t k = 0; k < addrToRead.size(); ++k)
+ if (readOnlyRegisters[j] == addrToRead[k])
+ {
+ dataReceived[k] &= readOnlyRegistersMasks[j];
+ break;
+ }
+
+ //check if local copy matches chip
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ {
+ if (dataReceived[i] != mRegistersMap->GetValue(0, addrToRead[i]))
+ {
+ isSynced = false;
+ goto isSyncedEnding;
+ }
+ }
+
+ addrToRead.clear(); //add only B channel addresses
+ addrToRead = mRegistersMap->GetUsedAddresses(1);
+
+ //mask out readonly bits
+ for (uint16_t j = 0; j < sizeof(readOnlyRegisters) / sizeof(uint16_t); ++j)
+ for (uint16_t k = 0; k < addrToRead.size(); ++k)
+ if (readOnlyRegisters[j] == addrToRead[k])
+ {
+ dataReceived[k] &= readOnlyRegistersMasks[j];
+ break;
+ }
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size());
+ if (status != LIBLMS7_SUCCESS)
+ return false;
+ //check if local copy matches chip
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ if (dataReceived[i] != mRegistersMap->GetValue(1, addrToRead[i]))
+ {
+ isSynced = false;
+ break;
+ }
+
+isSyncedEnding:
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //restore previously used channel
+ return isSynced;
+}
+
+/** @brief Writes all registers from host to chip
+
+When used on Novena board, also changes gpios to match rx path and tx band selections
+*/
+liblms7_status LMS7002M::UploadAll()
+{
+ if (controlPort == NULL)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC)); //remember used channel
+
+ liblms7_status status;
+
+ vector addrToWrite;
+ vector dataToWrite;
+
+ uint16_t x0020_value = mRegistersMap->GetValue(0, 0x0020);
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1); //select A channel
+
+ addrToWrite = mRegistersMap->GetUsedAddresses(0);
+ //remove 0x0020 register from list, to not change MAC
+ addrToWrite.erase( find(addrToWrite.begin(), addrToWrite.end(), 0x0020) );
+ for (auto address : addrToWrite)
+ dataToWrite.push_back(mRegistersMap->GetValue(0, address));
+
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ status = LIBLMS7_SUCCESS;
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ //after all channel A registers have been written, update 0x0020 register value
+ status = SPI_write(0x0020, x0020_value);
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ addrToWrite = mRegistersMap->GetUsedAddresses(1);
+ dataToWrite.clear();
+ for (auto address : addrToWrite)
+ {
+ dataToWrite.push_back(mRegistersMap->GetValue(1, address));
+ }
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2); //select B channel
+ status = SPI_write_batch(&addrToWrite[0], &dataToWrite[0], addrToWrite.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //restore last used channel
+
+ //in case of Novena board, need to update GPIO
+ if(controlPort->GetInfo().device == LMS_DEV_NOVENA)
+ {
+ uint16_t regValue = SPI_read(0x0706) & 0xFFF8;
+ //lms_gpio2 - tx output selection:
+ // 0 - TX1_A and TX1_B (Band 1),
+ // 1 - TX2_A and TX2_B (Band 2)
+ regValue |= Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF)) << 2; //gpio2
+ //RX active paths
+ //lms_gpio0 | lms_gpio1 RX_A RX_B
+ // 0 0 => no active path
+ // 1 0 => LNAW_A LNAW_B
+ // 0 1 => LNAH_A LNAH_B
+ // 1 1 => LNAL_A LNAL_B
+ switch(Get_SPI_Reg_bits(LMS7param(SEL_PATH_RFE)))
+ {
+ //set gpio1:gpio0
+ case 0: regValue |= 0x0; break;
+ case 1: regValue |= 0x2; break;
+ case 2: regValue |= 0x3; break;
+ case 3: regValue |= 0x1; break;
+ }
+ SPI_write(0x0706, regValue);
+ }
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Reads all registers from the chip to host
+
+When used on Novena board, also updates gpios to match rx path and tx band selections
+*/
+liblms7_status LMS7002M::DownloadAll()
+{
+ if (controlPort == nullptr)
+ return LIBLMS7_NO_CONNECTION_MANAGER;
+ if (controlPort->IsOpen() == false)
+ return LIBLMS7_NOT_CONNECTED;
+ liblms7_status status;
+ uint8_t ch = (uint8_t)Get_SPI_Reg_bits(LMS7param(MAC), false);
+
+ vector addrToRead = mRegistersMap->GetUsedAddresses(0);
+ vector dataReceived;
+ dataReceived.resize(addrToRead.size(), 0);
+ Modify_SPI_Reg_bits(LMS7param(MAC), 1);
+ status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ {
+ uint16_t adr = addrToRead[i];
+ uint16_t val = dataReceived[i];
+ mRegistersMap->SetValue(0, addrToRead[i], dataReceived[i]);
+ }
+
+ addrToRead.clear(); //add only B channel addresses
+ addrToRead = mRegistersMap->GetUsedAddresses(1);
+ dataReceived.resize(addrToRead.size(), 0);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), 2);
+ status = SPI_read_batch(&addrToRead[0], &dataReceived[0], addrToRead.size());
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+ for (uint16_t i = 0; i < addrToRead.size(); ++i)
+ mRegistersMap->SetValue(1, addrToRead[i], dataReceived[i]);
+
+ Modify_SPI_Reg_bits(LMS7param(MAC), ch); //retore previously used channel
+
+ //in case of Novena board, update GPIO
+ if(controlPort->GetInfo().device == LMS_DEV_NOVENA)
+ {
+ uint16_t regValue = SPI_read(0x0706) & 0xFFF8;
+ //lms_gpio2 - tx output selection:
+ // 0 - TX1_A and TX1_B (Band 1),
+ // 1 - TX2_A and TX2_B (Band 2)
+ regValue |= Get_SPI_Reg_bits(LMS7param(SEL_BAND2_TRF)) << 2; //gpio2
+ //RX active paths
+ //lms_gpio0 | lms_gpio1 RX_A RX_B
+ // 0 0 => no active path
+ // 1 0 => LNAW_A LNAW_B
+ // 0 1 => LNAH_A LNAH_B
+ // 1 1 => LNAL_A LNAL_B
+ switch(Get_SPI_Reg_bits(LMS7param(SEL_PATH_RFE)))
+ {
+ //set gpio1:gpio0
+ case 0: regValue |= 0x0; break;
+ case 1: regValue |= 0x2; break;
+ case 2: regValue |= 0x3; break;
+ case 3: regValue |= 0x1; break;
+ }
+ SPI_write(0x0706, regValue);
+ }
+
+ return LIBLMS7_SUCCESS;
+}
+
+/** @brief Configures interfaces for desired frequency
+ Sets interpolation and decimation, changes MCLK sources and TSP clock dividers accordingly to selected interpolation and decimation
+*/
+liblms7_status LMS7002M::SetInterfaceFrequency(float_type cgen_freq_MHz, const uint8_t interpolation, const uint8_t decimation)
+{
+ Modify_SPI_Reg_bits(LMS7param(HBD_OVR_RXTSP), decimation);
+ Modify_SPI_Reg_bits(LMS7param(HBI_OVR_TXTSP), interpolation);
+ liblms7_status status = SetFrequencyCGEN(cgen_freq_MHz);
+ if (status != LIBLMS7_SUCCESS)
+ return status;
+
+ if (decimation == 7 || decimation == 0) //bypass
+ {
+ Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), 0);
+ Modify_SPI_Reg_bits(LMS7param(RXDIVEN), false);
+ Modify_SPI_Reg_bits(LMS7param(MCLK2SRC), 3);
+ }
+ else
+ {
+ uint8_t divider = (uint8_t)pow(2.0, decimation);
+ if (divider > 1)
+ Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), (divider / 2) - 1);
+ else
+ Modify_SPI_Reg_bits(LMS7param(RXTSPCLKA_DIV), 0);
+ Modify_SPI_Reg_bits(LMS7param(RXDIVEN), true);
+ Modify_SPI_Reg_bits(LMS7param(MCLK2SRC), 1);
+ }
+ if (interpolation == 7 || interpolation == 0) //bypass
+ {
+ Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), 0);
+ Modify_SPI_Reg_bits(LMS7param(TXDIVEN), false);
+ Modify_SPI_Reg_bits(LMS7param(MCLK1SRC), 2);
+ }
+ else
+ {
+ uint8_t divider = (uint8_t)pow(2.0, interpolation);
+ if (divider > 1)
+ Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), (divider / 2) - 1);
+ else
+ Modify_SPI_Reg_bits(LMS7param(TXTSPCLKA_DIV), 0);
+ Modify_SPI_Reg_bits(LMS7param(TXDIVEN), true);
+ Modify_SPI_Reg_bits(LMS7param(MCLK1SRC), 0);
+ }
+ return status;
+}
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.h b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.h
new file mode 100644
index 0000000000..81234c28a3
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M.h
@@ -0,0 +1,177 @@
+/**
+@file LMS7002M.h
+@author Lime Microsystems (www.limemicro.com)
+@brief LMS7002M transceiver configuration interface
+*/
+
+#ifndef LMS7API_H
+#define LMS7API_H
+
+#include "LMS7002M_statuses.h"
+#include "LMS7002M_parameters.h"
+#include "typedefs.h"
+
+#include
+
+class LMScomms;
+class LMS7002M_RegistersMap;
+
+class LMS7002M
+{
+public:
+ enum
+ {
+ Rx, Tx
+ };
+
+ LMS7002M();
+ LMS7002M(LMScomms* controlPort);
+ virtual ~LMS7002M();
+
+ ///@name Registers writing and reading
+ liblms7_status UploadAll();
+ liblms7_status DownloadAll();
+ bool IsSynced();
+
+ liblms7_status ResetChip();
+ liblms7_status LoadConfig(const char* filename);
+ liblms7_status SaveConfig(const char* filename);
+ ///@}
+
+ ///@name Registers writing and reading
+ uint16_t Get_SPI_Reg_bits(const LMS7Parameter ¶m, bool fromChip = true);
+ uint16_t Get_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, bool fromChip = true);
+ liblms7_status Modify_SPI_Reg_bits(const LMS7Parameter ¶m, const uint16_t value, bool fromChip = true);
+ liblms7_status Modify_SPI_Reg_bits(uint16_t address, uint8_t msb, uint8_t lsb, uint16_t value, bool fromChip = true);
+ liblms7_status SPI_write(uint16_t address, uint16_t data);
+ uint16_t SPI_read(uint16_t address, bool fromChip = true, liblms7_status *status = 0);
+ liblms7_status RegistersTest();
+ ///@}
+
+ ///@name Transmitter, Receiver calibrations
+ liblms7_status CalibrateRx(float_type bandwidth_MHz);
+ liblms7_status CalibrateTx(float_type bandwidth_MHz);
+ ///@}
+
+ ///@name Filters tuning
+ enum TxFilter
+ {
+ TX_LADDER, TX_REALPOLE, TX_HIGHBAND
+ };
+ enum RxFilter
+ {
+ RX_TIA, RX_LPF_LOWBAND, RX_LPF_HIGHBAND
+ };
+ liblms7_status TuneTxFilter(TxFilter filterType, float_type bandwidth_MHz);
+ liblms7_status TuneTxFilterLowBandChain(float_type ladder_bw_MHz, float_type realpole_bw_MHz);
+ liblms7_status TuneRxFilter(RxFilter filterType, float_type bandwidth_MHz);
+ ///@}
+
+ ///@name CGEN and PLL
+ float_type GetReferenceClk_SX(bool tx);
+ float_type GetFrequencyCGEN_MHz();
+ liblms7_status SetFrequencyCGEN(float_type freq_MHz);
+ float_type GetFrequencySX_MHz(bool tx, float_type refClk_MHz);
+ liblms7_status SetFrequencySX(bool tx, float_type freq_MHz, float_type refClk_MHz);
+ ///VCO modules available for tuning
+ enum VCO_Module
+ {
+ VCO_CGEN, VCO_SXR, VCO_SXT
+ };
+ liblms7_status TuneVCO(VCO_Module module);
+ ///@}
+
+ ///@name TSP
+ liblms7_status LoadDC_REG_IQ(bool tx, int16_t I, int16_t Q);
+ liblms7_status SetNCOFrequency(bool tx, uint8_t index, float_type freq_MHz);
+ float_type GetNCOFrequency_MHz(bool tx, uint8_t index, float_type refClk_MHz, bool fromChip = true);
+ liblms7_status SetNCOPhaseOffsetForMode0(bool tx, float_type angle_Deg);
+ liblms7_status SetNCOPhaseOffset(bool tx, uint8_t index, float_type angle_Deg);
+ float_type GetNCOPhaseOffset_Deg(bool tx, uint8_t index);
+ liblms7_status SetGFIRCoefficients(bool tx, uint8_t GFIR_index, const int16_t *coef, uint8_t coefCount);
+ liblms7_status GetGFIRCoefficients(bool tx, uint8_t GFIR_index, int16_t *coef, uint8_t coefCount);
+ float_type GetReferenceClk_TSP_MHz(bool tx);
+ ///@}
+
+ liblms7_status SetInterfaceFrequency(float_type cgen_freq_MHz, const uint8_t interpolation, const uint8_t decimation);
+
+ ///enumeration to indicate module registers intervals
+ enum MemorySection
+ {
+ LimeLight = 0, EN_DIR, AFE, BIAS, XBUF, CGEN, LDO, BIST, CDS,
+ TRF, TBB, RFE, RBB, SX, TxTSP,
+ TxNCO, TxGFIR1, TxGFIR2, TxGFIR3a, TxGFIR3b, TxGFIR3c,
+ RxTSP, RxNCO, RxGFIR1, RxGFIR2, RxGFIR3a, RxGFIR3b, RxGFIR3c,
+ MEMORY_SECTIONS_COUNT
+ };
+ virtual liblms7_status SetDefaults(MemorySection module);
+ LMScomms* GetControlPort() const { return controlPort;};
+
+ static const float_type gLadder_lower_limit;
+ static const float_type gLadder_higher_limit;
+ static const float_type gRealpole_lower_limit;
+ static const float_type gRealpole_higher_limit;
+ static const float_type gHighband_lower_limit;
+ static const float_type gHighband_higher_limit;
+
+ static const float_type gRxTIA_higher_limit;
+ static const float_type gRxTIA_lower_limit_g1;
+ static const float_type gRxTIA_lower_limit_g23;
+ static const float_type gRxLPF_low_lower_limit;
+ static const float_type gRxLPF_low_higher_limit;
+ static const float_type gRxLPF_high_lower_limit;
+ static const float_type gRxLPF_high_higher_limit;
+
+ static float_type gVCO_frequency_table[3][2];
+ static float_type gCGEN_VCO_frequencies[2];
+
+ //protected:
+ LMS7002M_RegistersMap *mRegistersMap;
+ static const uint16_t readOnlyRegisters[];
+ static const uint16_t readOnlyRegistersMasks[];
+
+ uint16_t MemorySectionAddresses[MEMORY_SECTIONS_COUNT][2];
+ ///@name Algorithms functions
+ void BackupAllRegisters();
+ void RestoreAllRegisters();
+ uint32_t GetRSSI();
+ void SetRxDCOFF(int8_t offsetI, int8_t offsetQ);
+ uint32_t FindMinRSSI_Gain(const LMS7Parameter ¶m, uint16_t *foundValue);
+ uint32_t FindMinRSSI(const LMS7Parameter ¶m, const int16_t startValue, int16_t *result, const uint8_t scanWidth, const uint8_t twoCompl, int8_t stepMult = 1);
+ uint32_t FindMinRSSI(const uint16_t addr, const uint8_t msb, const uint8_t lsb, const int16_t startValue, int16_t *result, const uint8_t scanWidth, const uint8_t twoCompl, int8_t stepMult = 1);
+ void CalibrateRxDC_RSSI();
+ liblms7_status CalibrateTxSetup(float_type bandwidth_MHz);
+ liblms7_status CalibrateRxSetup(float_type bandwidth_MHz);
+ liblms7_status FixRXSaturation();
+ void FilterTuning_AdjustGains();
+ liblms7_status TuneTxFilterSetup(TxFilter type, float_type cutoff_MHz);
+ liblms7_status TuneRxFilterSetup(RxFilter type, float_type cutoff_MHz);
+ liblms7_status RFE_TIA_Calibration(float_type TIA_freq_MHz);
+ liblms7_status RxLPFLow_Calibration(float_type RxLPFL_freq_MHz);
+ liblms7_status RxLPFHigh_Calibration(float_type RxLPFH_freq_MHz);
+
+ liblms7_status RegistersTestInterval(uint16_t startAddr, uint16_t endAddr, uint16_t pattern, std::stringstream &ss);
+ liblms7_status SPI_write_batch(const uint16_t* spiAddr, const uint16_t* spiData, uint16_t cnt);
+ liblms7_status SPI_read_batch(const uint16_t* spiAddr, uint16_t* spiData, uint16_t cnt);
+ liblms7_status Modify_SPI_Reg_mask(const uint16_t *addr, const uint16_t *masks, const uint16_t *values, uint8_t start, uint8_t stop);
+ ///@}
+ ///Reference clock used for Receiver frequency calculations
+ float_type mRefClkSXR_MHz;
+ ///Reference clock used for Transmitter frequency calculations
+ float_type mRefClkSXT_MHz;
+
+ enum LogType
+ {
+ LOG_INFO,
+ LOG_WARNING,
+ LOG_ERROR,
+ LOG_DATA
+ };
+ virtual void Log(const char* text, LogType type);
+
+ ///port used for communicating with LMS7002M
+ LMScomms* controlPort;
+
+ liblms7_status LoadConfigLegacyFile(const char* filename);
+};
+#endif
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.cpp b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.cpp
new file mode 100644
index 0000000000..8c870ffcc0
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.cpp
@@ -0,0 +1,68 @@
+#include "LMS7002M_RegistersMap.h"
+#include "LMS7002M_parameters.h"
+
+LMS7002M_RegistersMap::LMS7002M_RegistersMap()
+{
+
+}
+
+LMS7002M_RegistersMap::~LMS7002M_RegistersMap()
+{
+
+}
+
+uint16_t LMS7002M_RegistersMap::GetDefaultValue(uint16_t address) const
+{
+ std::map::const_iterator iter = mChannelA.find(address);
+ if( iter != mChannelA.end())
+ return iter->second.defaultValue;
+ else
+ return 0;
+}
+
+void LMS7002M_RegistersMap::InitializeDefaultValues(const std::vector parameterList)
+{
+ for(auto parameter : parameterList)
+ {
+ uint16_t regValue = mChannelA[parameter->address].defaultValue;
+ mChannelA[parameter->address].defaultValue = regValue | (parameter->defaultValue << parameter->lsb);
+ mChannelA[parameter->address].value = mChannelA[parameter->address].defaultValue;
+ if(parameter->address >= 0x0100)
+ mChannelB[parameter->address].value = mChannelA[parameter->address].value;
+ }
+}
+
+void LMS7002M_RegistersMap::SetValue(uint8_t channel, const uint16_t address, const uint16_t value)
+{
+ if(channel == 0)
+ mChannelA[address].value = value;
+ else if(channel == 1)
+ mChannelB[address].value = value;
+}
+
+uint16_t LMS7002M_RegistersMap::GetValue(uint8_t channel, uint16_t address) const
+{
+ const std::map *regMap;
+ if(channel == 0)
+ regMap = &mChannelA;
+ else if(channel == 1)
+ regMap = &mChannelB;
+ std::map::const_iterator iter;
+ iter = regMap->find(address);
+ if (iter != regMap->end())
+ return iter->second.value;
+ else
+ return 0;
+}
+
+std::vector LMS7002M_RegistersMap::GetUsedAddresses(const uint8_t channel) const
+{
+ std::vector addresses;
+ if(channel == 0)
+ for(auto iter : mChannelA)
+ addresses.push_back(iter.first);
+ else if(channel == 1)
+ for(auto iter : mChannelB)
+ addresses.push_back(iter.first);
+ return addresses;
+}
diff --git a/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.h b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.h
new file mode 100644
index 0000000000..5ccda752db
--- /dev/null
+++ b/targets/ARCH/LMSSDR/USERSPACE/LIB/lms7002m/LMS7002M_RegistersMap.h
@@ -0,0 +1,35 @@
+#ifndef LMS7002M_REGISTERS_MAP_H
+#define LMS7002M_REGISTERS_MAP_H
+
+#include
+#include