diff --git a/.gitignore b/.gitignore index 796b96d..7f7adc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /build +/.vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5a0aee9..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "files.associations": { - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "array": "cpp", - "atomic": "cpp", - "strstream": "cpp", - "*.tcc": "cpp", - "bitset": "cpp", - "cfenv": "cpp", - "chrono": "cpp", - "cinttypes": "cpp", - "codecvt": "cpp", - "complex": "cpp", - "condition_variable": "cpp", - "cstdint": "cpp", - "deque": "cpp", - "forward_list": "cpp", - "list": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "map": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "set": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "shared_mutex": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "thread": "cpp", - "typeindex": "cpp", - "typeinfo": "cpp", - "bit": "cpp" - } -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ec2d0d..860fad3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ message("CMNALIB_LIBRARIES: " ${CMNALIB_LIBRARIES}) # cmnalib also needs glib: INCLUDE(FindPkgConfig) -pkg_check_modules(GLIB2 REQUIRED glib-2.0) +pkg_check_modules(GLIB2 REQUIRED glib-2.0) include_directories(${GLIB2_INCLUDE_DIRS}) #link_directories(${GLIB2_LIBRARY_DIRS}) @@ -176,6 +176,9 @@ else(SRSRAN_FOUND AND NOT FORCE_SUBPROJECT_SRSRAN) message("Download SRSRAN as a subproject and build it.") # Download and unpack srsRAN at configure time + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/srsRAN-src") + file(COPY "${CMAKE_SOURCE_DIR}/srsRAN_4G_mirror/" DESTINATION "${CMAKE_BINARY_DIR}/srsRAN-src") + configure_file(external/cmake/srsRAN.CMakeLists.txt.in srsRAN-download/CMakeLists.txt) execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/srsRAN-download" ) @@ -272,7 +275,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") message("MARCH - FLAGS: ${GCC_ARCH}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${GCC_ARCH} -Wall -Wno-comment -Wno-write-strings -Winline -Wno-unused-result -Wformat -Wmissing-field-initializers -Wtype-limits -std=c99 -D_GNU_SOURCE") - find_package(SSE) # evaluation comes later + find_package(SSE) # evaluation comes later if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG") @@ -292,7 +295,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFORCE_STANDARD_RATE") endif (USE_LTE_RATES) - #find_package(SSE) # moved upwards before BUILD_TYPE-specific flags. -> AVX512 detection/test code gets subject of O3 optimization -> reports availability even if not present + #find_package(SSE) # moved upwards before BUILD_TYPE-specific flags. -> AVX512 detection/test code gets subject of O3 optimization -> reports availability even if not present if (HAVE_AVX2) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -mavx2 -DLV_HAVE_AVX2 -DLV_HAVE_AVX -DLV_HAVE_SSE") else (HAVE_AVX2) @@ -380,7 +383,7 @@ set(INCLUDE_DIR include) # PATH to usr/local/include for install ######################################################################## include_directories(${PROJECT_BINARY_DIR}/lib/include) include_directories(${PROJECT_SOURCE_DIR}/lib/include) -include_directories(${PROJECT_SOURCE_DIR}/src) # for cross includes of top-level applications +include_directories(${PROJECT_SOURCE_DIR}/src) # for cross includes of top-level applications include_directories(${PROJECT_SOURCE_DIR}/lib) ######################################################################## # Add the subdirectories diff --git a/external/cmake/srsRAN.CMakeLists.txt.in b/external/cmake/srsRAN.CMakeLists.txt.in index 247f220..e78a44b 100644 --- a/external/cmake/srsRAN.CMakeLists.txt.in +++ b/external/cmake/srsRAN.CMakeLists.txt.in @@ -5,8 +5,8 @@ project(srsLTE-download NONE) include(ExternalProject) ExternalProject_Add(srsRAN - GIT_REPOSITORY https://github.com/ShaoPaoLao/srsRAN2.git - GIT_TAG master +# GIT_REPOSITORY https://github.com/ShaoPaoLao/srsRAN2.git +# GIT_TAG master # GIT_TAG falcon_v0.1 SOURCE_DIR "${CMAKE_BINARY_DIR}/srsRAN-src" BINARY_DIR "${CMAKE_BINARY_DIR}/srsRAN-build" diff --git a/lib/include/falcon/util/RNTIManager.h b/lib/include/falcon/util/RNTIManager.h index 2413796..71ad768 100644 --- a/lib/include/falcon/util/RNTIManager.h +++ b/lib/include/falcon/util/RNTIManager.h @@ -31,6 +31,9 @@ #include "Histogram.h" #include "Interval.h" +#include + +#include // DCI minimum average llr for accepting DCI for blind decoding //#define DCI_MINIMUM_AVG_LLR_BOUND 0.5 //0.5 @@ -108,7 +111,7 @@ class RNTIManager { std::vector > evergreen; std::vector > forbidden; std::vector active; - std::list activeSet; + std::map activeSet; std::vector lastSeen; std::vector assocFormatIdx; uint32_t timestamp; @@ -116,4 +119,6 @@ class RNTIManager { uint32_t threshold; uint32_t maxCandidatesPerStepPerFormat; std::vector remainingCandidates; + + std::mutex rnti_mutex; }; diff --git a/lib/src/util/RNTIManager.cc b/lib/src/util/RNTIManager.cc index 9261cc3..733a237 100644 --- a/lib/src/util/RNTIManager.cc +++ b/lib/src/util/RNTIManager.cc @@ -215,8 +215,12 @@ uint32_t RNTIManager::getAssociatedFormatIdx(uint16_t rnti) { } ActivationReason RNTIManager::getActivationReason(uint16_t rnti) { - for(list::iterator it = activeSet.begin(); it != activeSet.end(); it++) { - if(it->rnti == rnti) return it->reason; + std::lock_guard lock(rnti_mutex); + std::map::const_iterator pos = activeSet.find(rnti); + if (pos == activeSet.end()) { + //handle the error + } else { + return pos->second.reason; } return RM_ACT_UNSET; } @@ -225,11 +229,11 @@ vector RNTIManager::getActiveSet() { cleanExpired(); vector result(activeSet.size()); uint32_t index = 0; - for(list::iterator it = activeSet.begin(); it != activeSet.end(); it++) { - result[index].rnti = it->rnti; - result[index].reason = it->reason; - result[index].last_seen = timestamp - lastSeen[it->rnti]; - result[index].assoc_format_idx = getAssociatedFormatIdx(it->rnti); + for(map::iterator it = activeSet.begin(); it != activeSet.end(); it++) { + result[index].rnti = it->second.rnti; + result[index].reason = it->second.reason; + result[index].last_seen = timestamp - lastSeen[it->second.rnti]; + result[index].assoc_format_idx = getAssociatedFormatIdx(it->second.rnti); result[index].frequency = getFrequency(result[index].rnti, result[index].assoc_format_idx); if(result[index].assoc_format_idx != 0) { result[index].frequency += getFrequency(result[index].rnti, 0); @@ -377,7 +381,9 @@ uint32_t RNTIManager::getLikelyDlFormatIdx(uint16_t rnti) { void RNTIManager::activateRNTI(uint16_t rnti, ActivationReason reason) { if(!active[rnti]) { active[rnti] = true; - activeSet.push_back(RNTIActiveSetItem(rnti, reason)); + std::unique_lock lock(rnti_mutex); + activeSet.insert({rnti,RNTIActiveSetItem(rnti, reason)}); + lock.unlock(); } } @@ -385,7 +391,9 @@ void RNTIManager::deactivateRNTI(uint16_t rnti) { if(active[rnti]) { active[rnti] = false; assocFormatIdx[rnti] = 0; - activeSet.remove(RNTIActiveSetItem(rnti)); + std::unique_lock lock(rnti_mutex); + activeSet.erase(rnti); + lock.unlock(); } } @@ -400,13 +408,15 @@ bool RNTIManager::isExpired(uint16_t rnti) const { } void RNTIManager::cleanExpired() { - list::iterator it = activeSet.begin(); + map::iterator it = activeSet.begin(); while(it != activeSet.end()) { - if(isExpired(it->rnti)) { + if(isExpired(it->second.rnti)) { + std::unique_lock lock(rnti_mutex); it = activeSet.erase(it); + lock.unlock(); } else { - ++it; + it++; } } } diff --git a/run_default.sh b/run_default.sh new file mode 100755 index 0000000..2fab8e4 --- /dev/null +++ b/run_default.sh @@ -0,0 +1,2 @@ +#!/bin/bash +/home/LTESniffer_mirror/build/src/LTESniffer -a addr=192.168.30.2,type=x300,clock_source=external,time_source=external -d -A 2 -W 16 -f 2130e6 -u 1730e6 -C -m 2 -z 3 diff --git a/src/LTESniffer.cc b/src/LTESniffer.cc index 92a6218..be6ed17 100644 --- a/src/LTESniffer.cc +++ b/src/LTESniffer.cc @@ -14,9 +14,22 @@ using namespace std; int main(int argc, char** argv) { cout << endl; - cout << "LTESniffer" << endl; + cout << "LTESniffer Start!!!" << endl; cout << endl; + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + for(std::string::iterator it = str_cur_time.begin(); it != str_cur_time.end(); ++it) { + if (*it == ' '){ + *it = '_'; + } else if (*it == ':'){ + *it = '.'; + } else if (*it == '\n'){ + *it = '.'; + } + } + Args args; ArgManager::parseArgs(args, argc, argv); @@ -29,5 +42,9 @@ int main(int argc, char** argv) { bool success = SnifferCore.run(); + cout << endl; + cout << "LTESniffer End!!!" << endl; + cout << endl; + return success ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/include/DL_Sniffer_PDSCH.h b/src/include/DL_Sniffer_PDSCH.h index 2a52cc6..8facbf0 100644 --- a/src/include/DL_Sniffer_PDSCH.h +++ b/src/include/DL_Sniffer_PDSCH.h @@ -65,6 +65,7 @@ class PDSCH_Decoder public: PDSCH_Decoder(uint32_t idx, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, RNTIManager& rntiManager, HARQ *harq, @@ -149,7 +150,7 @@ class PDSCH_Decoder void set_target_rnti(uint16_t rnti) {target_rnti = rnti;} void set_debug_mode(bool debug) { en_debug = debug;} void set_api_mode(int api_mode_) { api_mode = api_mode_;} - void print_api_dl(uint32_t tti, uint16_t rnti, int ident, std::string value, int msg); + void print_api_dl(uint32_t tti, uint16_t rnti, int ident, std::string value, int msg, uint32_t ta_rnti); private: int api_mode = -1; @@ -174,6 +175,7 @@ class PDSCH_Decoder srsran_pdsch_res_t *pdsch_res; srsran_pdsch_cfg_t *pdsch_cfg; //buffer LTESniffer_pcap_writer *pcapwriter; + std::vector *filewriter_objs; RNTIManager &rntiManager; int mcs_tracking_mode; MCSTracking *mcs_tracking; diff --git a/src/include/FileWriter.h b/src/include/FileWriter.h new file mode 100644 index 0000000..2577f0a --- /dev/null +++ b/src/include/FileWriter.h @@ -0,0 +1,22 @@ +/* + * LTE DL_Snifer BWS addition + */ +#pragma once +#include + +// Define a new class for creating a new thread of stat +class LTESniffer_stat_writer +{ +public: + LTESniffer_stat_writer() {enable_write=false; stat_file = NULL; }; + void enable(bool en); + void open(const std::string filename); + void close(); + void write_stats(std::string); + +private: + std::mutex stat_mutex; + bool enable_write; + FILE *stat_file; + void writer(std::string); +}; \ No newline at end of file diff --git a/src/include/LTESniffer_Core.h b/src/include/LTESniffer_Core.h index 00dd81e..c07c0e1 100644 --- a/src/include/LTESniffer_Core.h +++ b/src/include/LTESniffer_Core.h @@ -33,6 +33,7 @@ #include "srsran/common/mac_pcap.h" #include "Phy.h" #include "PcapWriter.h" +#include "FileWriter.h" #include "HARQ.h" #include #include @@ -65,6 +66,9 @@ using namespace srsran; #define UL_SNIFFER_UL_OFFSET_32 32 #define UL_SNIFFER_UL_OFFSET_64 64 +void write_file_and_console(std::string mystring, LTESniffer_stat_writer* filewriter_obj); +void cell_print(LTESniffer_stat_writer* filewriter_obj, srsran_cell_t* cell, uint32_t sfn); + typedef struct { cf_t* ta_temp_buffer; cf_t ta_last_sample[UL_SNIFFER_UL_MAX_OFFSET]; @@ -95,7 +99,7 @@ class LTESniffer_Core : public SignalHandler { void resetDCIConsumer(); void refreshShortcutDiscovery(bool val); void setRNTIThreshold(int val); - void print_api_header(); + void print_api_header(LTESniffer_stat_writer *filewriter_obj); bool run(); void stop(); private: @@ -111,6 +115,16 @@ class LTESniffer_Core : public SignalHandler { std::mutex harq_map_mutex; Phy *phy; LTESniffer_pcap_writer pcapwriter; + FILE * errfile; + //FILE * outfile; + std::vector filewriter_objs; + LTESniffer_stat_writer apiwriter; + LTESniffer_stat_writer dlwriter; + LTESniffer_stat_writer dldciwriter; + LTESniffer_stat_writer ulwriter; + LTESniffer_stat_writer uldciwriter; + LTESniffer_stat_writer rarwriter; + LTESniffer_stat_writer otherwriter; srsran::mac_pcap mac_pcap; int mcs_tracking_mode; MCSTracking mcs_tracking; diff --git a/src/include/MCSTracking.h b/src/include/MCSTracking.h index 51d26f2..4e2f66b 100644 --- a/src/include/MCSTracking.h +++ b/src/include/MCSTracking.h @@ -21,6 +21,7 @@ #endif #include "falcon/phy/falcon_phch/falcon_dci.h" +#include "FileWriter.h" #ifdef __cplusplus } @@ -107,9 +108,9 @@ class MCSTracking void update_RNTI_ul(uint16_t RNTI, ul_sniffer_mod_tracking_t mcs_mod); void update_database_ul(); int nof_RNTI_member_ul(){ return tracking_database_ul_mode.size();} - void print_database_ul(); + void print_database_ul(LTESniffer_stat_writer *filewriter_obj, int api_mode); void merge_all_database_ul(); - void print_all_database_ul(); + void print_all_database_ul(LTESniffer_stat_writer *filewriter_obj, int api_mode); void update_statistic_ul(uint16_t RNTI, bool success, DCI_UL &decoding_mem, float snr, float ta); /*DL 256QAM/64QAM tracking implementation*/ @@ -118,9 +119,9 @@ class MCSTracking void update_RNTI_dl(uint16_t RNTI, dl_sniffer_mcs_table_t mcs_table); void update_database_dl(); int nof_RNTI_member_dl(){ return tracking_database_dl_mode.size();} - void print_database_dl(); + void print_database_dl(LTESniffer_stat_writer *filewriter_obj, int api_mode); void merge_all_database_dl(); - void print_all_database_dl(); + void print_all_database_dl(LTESniffer_stat_writer *filewriter_obj, int api_mode); void update_rar_time_crnti(uint16_t crnti, clock_t cur_time); void update_statistic_dl(uint16_t RNTI, bool tb_en[SRSRAN_MAX_CODEWORDS], @@ -132,7 +133,7 @@ class MCSTracking /*Manage UE-specific-configuration*/ void update_ue_config_rnti(uint16_t rnti, ltesniffer_ue_spec_config_t ue_spec_config); - ltesniffer_ue_spec_config_t get_ue_config_rnti(uint16_t rnti); + ltesniffer_ue_spec_config_t get_ue_config_rnti(uint16_t rnti, int DL_or_UL); void update_default_ue_config(ltesniffer_ue_spec_config_t ue_spec_config); double get_interval() { return interval;} diff --git a/src/include/Phy.h b/src/include/Phy.h index db2baa2..5a807d9 100644 --- a/src/include/Phy.h +++ b/src/include/Phy.h @@ -29,6 +29,7 @@ class Phy { double metaFormatSplitRatio, uint32_t histogramThreshold, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, HARQ *harq, int mcs_tracking_mode, diff --git a/src/include/Sniffer_dependency.h b/src/include/Sniffer_dependency.h index 6e007e6..0e83b49 100644 --- a/src/include/Sniffer_dependency.h +++ b/src/include/Sniffer_dependency.h @@ -5,6 +5,8 @@ #include #include +#include "include/Sniffer_file_defs.h" + // include C-only headers #ifdef __cplusplus extern "C" { @@ -36,8 +38,17 @@ #define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */ #define BOLDWHITE "\033[1m\033[37m" /* Bold White */ + #define DL_MODE 0 #define UL_MODE 1 +#define DL_UL_MODE 2 + +#define DEBUG_DCI_PRINT 0 // default not print to screen +#define DEBUG_TABLE_PRINT 1 // default print when no SEC/API +#define DEBUG_SEC_PRINT 1 // default print if active +#define FILE_WRITE 1 // write everything to file + +#define UHD_FAIL_LIMIT 5 #define ID_RAN_VAL 0 #define ID_TMSI 1 @@ -52,6 +63,7 @@ #define MSG_ID_RES 3 #define MSG_UE_CAP 4 #define MSG_PAGING 5 +#define MSG_RAR 6 struct DCI_BASE { DCI_BASE(); diff --git a/src/include/Sniffer_file_defs.h b/src/include/Sniffer_file_defs.h new file mode 100644 index 0000000..1894f51 --- /dev/null +++ b/src/include/Sniffer_file_defs.h @@ -0,0 +1,7 @@ +#define FILE_IDX_API 0 +#define FILE_IDX_DL 1 +#define FILE_IDX_DL_DCI 2 +#define FILE_IDX_UL 3 +#define FILE_IDX_UL_DCI 4 +#define FILE_IDX_RAR 5 +#define FILE_IDX_CONTROL 6 \ No newline at end of file diff --git a/src/include/SubframeWorker.h b/src/include/SubframeWorker.h index 4ce969d..3068468 100644 --- a/src/include/SubframeWorker.h +++ b/src/include/SubframeWorker.h @@ -20,6 +20,7 @@ class SubframeWorker { PhyCommon& common, DCIMetaFormats& metaFormats, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, HARQ *harq, int mcs_tracking_mode, @@ -65,6 +66,7 @@ class SubframeWorker { bool collision_dw, collision_up; DCIBlindSearchStats stats; LTESniffer_pcap_writer *pcapwriter; + std::vector *filewriter_objs; PDSCH_Decoder *pdschdecoder; int mcs_tracking_mode; MCSTracking *mcs_tracking; diff --git a/src/include/UL_Sniffer_PUSCH.h b/src/include/UL_Sniffer_PUSCH.h index 259e966..36aad9c 100644 --- a/src/include/UL_Sniffer_PUSCH.h +++ b/src/include/UL_Sniffer_PUSCH.h @@ -51,6 +51,7 @@ class PUSCH_Decoder cf_t** buffer_offset, srsran_ul_cfg_t &ul_cfg, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcstracking, bool en_debug); ~PUSCH_Decoder(); @@ -69,15 +70,18 @@ class PUSCH_Decoder /*Investigate UL grant before decoding it*/ int check_valid_prb_ul(uint32_t nof_prb); int investigate_valid_ul_grant(DCI_UL &decoding_mem); + int investigate_valid_ul_grant_256(DCI_UL &decoding_mem); void decode_run(std::string info, DCI_UL &decoding_mem, std::string mod, float falcon_signal_power); void set_configed() { configed = true;} bool get_configed() { return configed;} + std::string dci_format_ul(int format); std::string modulation_mode_string(int mode, bool max_64qam); std::string modulation_mode_string_256(int idx); void print_debug(DCI_UL &decoding_mem, + std::string format, std::string offset_name, std::string modulation_mode, float signal_pw, @@ -109,10 +113,12 @@ class PUSCH_Decoder std::vector *dci_ul; std::vector *rar_dci_ul; int valid_ul_grant = SRSRAN_ERROR; + int valid_ul_grant_256 = SRSRAN_ERROR; srsran_enb_ul_t &enb_ul; srsran_ul_sf_cfg_t &ul_sf; LTESniffer_pcap_writer *pcapwriter; + std::vector *filewriter_objs; srsran_pusch_res_t pusch_res = {}; srsran_ul_cfg_t &ul_cfg; diff --git a/src/src/DCICollection.cc b/src/src/DCICollection.cc index cb37eef..941939f 100644 --- a/src/src/DCICollection.cc +++ b/src/src/DCICollection.cc @@ -115,7 +115,7 @@ void DCICollection::addCandidate(dci_candidate_t& cand, { ran_dci_dl->mcs_table = DL_SNIFFER_64QAM_TABLE; } else { - if (sniffer_mode == DL_MODE){ + if ((sniffer_mode == DL_MODE)||(sniffer_mode == DL_UL_MODE)){ ran_dci_dl->mcs_table = mcs_tracking->find_tracking_info_RNTI_dl(cand.rnti); }else{ ran_dci_dl->mcs_table = DL_SNIFFER_UNKNOWN_TABLE; diff --git a/src/src/DL_Sniffer_PDSCH.cc b/src/src/DL_Sniffer_PDSCH.cc index 9643893..050cd8a 100644 --- a/src/src/DL_Sniffer_PDSCH.cc +++ b/src/src/DL_Sniffer_PDSCH.cc @@ -1,9 +1,11 @@ #include "include/DL_Sniffer_PDSCH.h" +#include "include/Sniffer_dependency.h" float p_a_array[8]{-6, -4.77, -3, -1.77, 0, 1, 2, 3}; PDSCH_Decoder::PDSCH_Decoder(uint32_t idx, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, RNTIManager &rntiManager, HARQ *harq, @@ -20,6 +22,7 @@ PDSCH_Decoder::PDSCH_Decoder(uint32_t idx, pdsch_res(), pdsch_cfg(), pcapwriter(pcapwriter), + filewriter_objs(filewriter_objs), mcs_tracking(mcs_tracking), rntiManager(rntiManager), harq(harq), @@ -103,7 +106,7 @@ int PDSCH_Decoder::decode_imsi_tmsi_paging(uint8_t *sdu_ptr, int length) { uint8_t temp_imsi = paging_record.ue_id.imsi()[k]; imsi_str.append(std::to_string(temp_imsi)); - print_api_dl(dl_sf->tti, 65534, ID_IMSI, imsi_str, MSG_PAGING); + print_api_dl(dl_sf->tti, 65534, ID_IMSI, imsi_str, MSG_PAGING, -1); mcs_tracking->increase_nof_api_msg(); ret = SRSRAN_SUCCESS; } @@ -116,7 +119,7 @@ int PDSCH_Decoder::decode_imsi_tmsi_paging(uint8_t *sdu_ptr, int length) std::stringstream ss; ss << std::hex << m_tmsi; std::string m_tmsi_str = ss.str(); - print_api_dl(dl_sf->tti, 65534, ID_TMSI, m_tmsi_str, MSG_PAGING); + print_api_dl(dl_sf->tti, 65534, ID_TMSI, m_tmsi_str, MSG_PAGING, -1); mcs_tracking->increase_nof_api_msg(); ret = SRSRAN_SUCCESS; } @@ -282,7 +285,7 @@ int PDSCH_Decoder::run_decode(int &mimo_ret, std::string con_res_str = temp_con_res_str.substr(3, 8); // printf("[API] SF: %d-%d Found RRC Connection Setup, Contention Resolution = %s, RNTI = %d \n", // tti/10, tti%10, con_res_str.c_str(), cur_rnti); - print_api_dl(tti, cur_rnti, ID_CON_RES, con_res_str, MSG_CON_SET); + print_api_dl(tti, cur_rnti, ID_CON_RES, con_res_str, MSG_CON_SET, -1); mcs_tracking->increase_nof_api_msg(); found_res = true; } @@ -332,6 +335,15 @@ int PDSCH_Decoder::decode_ul_mode(uint32_t rnti, std::vectortti, result.t_crnti, MSG_RAR, ta_str, MSG_RAR, cur_rnti); + //print_api_dl(dl_sf->tti, cur_rnti, MSG_RAR, ta_str, MSG_RAR); + } rar_result->push_back(std::move(result)); } else @@ -600,13 +612,6 @@ int PDSCH_Decoder::unpack_rar_response_ul_mode(uint8_t *payload, int length, DL_ ul_sf.tti = dl_sf->tti; ul_sniffer_ra_ul_dci_to_grant(&falcon_ue_dl->q->cell, &ul_sf, &hopping_cfg, &dci_ul, &result.ran_ul_grant); rntiManager.activateAndRefresh(result.t_crnti, 0, ActivationReason::RM_ACT_RAR); // add RNTI in RAR response to active list - // std::cout << " RAR: " << "TA = " << result.ta; - // std::cout << " -- T-CRNTI: " << result.t_crnti; - // std::cout << " -- GRANT: "; - // for (int g = 0; g < 20; g++){ - // std::cout << unsigned(result.grant[g]) << " "; - // } - // std::cout << std::endl; ret = SRSRAN_SUCCESS; } } @@ -789,7 +794,7 @@ int PDSCH_Decoder::decode_dl_mode() { pdsch_res[tb].crc = false; } - ltesniffer_ue_spec_config_t ue_config = mcs_tracking->get_ue_config_rnti(cur_rnti); // find p_a from database + ltesniffer_ue_spec_config_t ue_config = mcs_tracking->get_ue_config_rnti(cur_rnti, 0); // find p_a from database pdsch_cfg->p_a = ue_config.p_a; // update p_a from database bool tb_en[SRSRAN_MAX_CODEWORDS]{cur_grant->tb[0].enabled, cur_grant->tb[1].enabled}; int mimo_ret = SRSRAN_SUCCESS; @@ -897,6 +902,7 @@ int PDSCH_Decoder::decode_dl_mode() std::string dci_fm = dci_format(cur_format); std::string mod = mod_sche(cur_grant->tb[tb].mod); std::string table_name = decoding_mem.mcs_table ? ("256") : ("64"); + table_name = "[" + table_name + "]"; if (pdsch_res[tb].crc && result_length > 0) { write_pcap(RNTI_name, pdsch_res[tb].payload, result_length, cur_rnti, tti, 0); @@ -1029,7 +1035,7 @@ int PDSCH_Decoder::decode_dl_mode() } if (cur_rnti != 65535 && cur_grant->tb[tb].enabled && (target_rnti == 0 || cur_rnti == target_rnti) && en_debug) { - print_debug_dl("Unkown64", tti, decoding_mem.rnti, dci_fm, mod, decoding_mem.ran_dci_dl->tb[0].mcs_idx, harq_ret[tb], + print_debug_dl("[Unknown-64]", tti, decoding_mem.rnti, dci_fm, mod, decoding_mem.ran_dci_dl->tb[0].mcs_idx, harq_ret[tb], nof_tb, result_length, pdsch_res[tb].crc, &falcon_ue_dl->q->chest_res); } } @@ -1088,7 +1094,7 @@ int PDSCH_Decoder::decode_dl_mode() } if (cur_rnti != 65535 && cur_grant256->tb[tb].enabled && (target_rnti == 0 || cur_rnti == target_rnti) && en_debug) { - print_debug_dl("Unkown256", tti, decoding_mem.rnti, dci_fm, mod, decoding_mem.ran_dci_dl->tb[0].mcs_idx, harq_ret[tb], + print_debug_dl("[Unknown-256]", tti, decoding_mem.rnti, dci_fm, mod, decoding_mem.ran_dci_dl->tb[0].mcs_idx, harq_ret[tb], nof_tb, result_length, pdsch_res[tb].crc, &falcon_ue_dl->q->chest_res); } } @@ -1146,6 +1152,7 @@ int PDSCH_Decoder::decode_dl_mode() return SRSRAN_SUCCESS; } +// FIO FILE_IDX_DL_DCI void PDSCH_Decoder::print_debug_dl(std::string name, int tti, uint16_t rnti, @@ -1158,33 +1165,52 @@ void PDSCH_Decoder::print_debug_dl(std::string name, bool result, srsran_chest_dl_res_t *ce_res) { - std::cout << std::left << std::setw(9) << name; - std::cout << "SF:" << std::left << std::setw(4) << tti / 10 << "-" << tti % 10; - // std::cout << "[" << std::left << std::setw(2) << idx << "]"; - std::cout << GREEN << " -- RNTI: " << std::left << std::setw(5) << rnti << RESET; - std::cout << WHITE << " -- DCI: " << std::left << std::setw(4) << format << RESET; - std::cout << YELLOW << " -- Mod: " << std::left << std::setw(6) << mod << RESET; - std::cout << " -- MCS: " << std::left << std::setw(3) << mcs_idx; + std::stringstream msg; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(15) << name; + msg << "SF:" << std::left << std::setw(4) << tti / 10 << "-" << tti % 10; + // msg << "[" << std::left << std::setw(2) << idx << "]"; + msg << GREEN << " -- RNTI: " << std::left << std::setw(5) << rnti << RESET; + msg << WHITE << " -- DCI: " << std::left << std::setw(4) << format << RESET; + msg << YELLOW << " -- Mod: " << std::left << std::setw(6) << mod << RESET; + msg << " -- MCS: " << std::left << std::setw(3) << mcs_idx; // std::string re_tx = retx?(" -- reTX"):(" -- NewTX"); - // std::cout << RED << std::left << std::setw(9) << re_tx << RESET; - std::cout << CYAN << " -- nof_TB: " << std::left << pdsch_cfg->grant.nof_tb << RESET; - std::cout << BLUE << " -- Byte: " << std::left << std::setw(5) << length << RESET; - // std::cout << std::setprecision(2) << GREEN << " -- rsrp: " << ce_res->rsrp_dbm << " --rsrq: " \ - // << ce_res->rsrq_db << " --SNR: " << ce_res->snr_db << " --CFO: " << ce_res->cfo << RESET; - std::cout << " -- Antenna SNR: " << std::left << std::setw(4) << ce_res->snr_ant_port_db[0][0] - << "|" << std::setw(4) << ce_res->snr_ant_port_db[1][1] << RESET; - std::cout << " -- SNR: " << std::left << std::setprecision(3) << std::setw(5) << ce_res->snr_db << RESET; - std::cout << RESET << " -- Result: "; + // msg << RED << std::left << std::setw(9) << re_tx << RESET; + msg << CYAN << " -- nof_TB: " << std::left << pdsch_cfg->grant.nof_tb << RESET; + msg << BLUE << " -- Byte: " << std::left << std::setw(5) << length << RESET; + // msg << std::setprecision(2) << GREEN << " -- rsrp: " << ce_res->rsrp_dbm << " --rsrq: " \ + // << ce_res->rsrq_db << " --SNR: " << ce_res->snr_db << " --CFO: " << ce_res->cfo << RESET; + msg << " -- Antenna SNR: " << std::left << std::setw(4) << ce_res->snr_ant_port_db[0][0] + << "|" << std::setw(4) << ce_res->snr_ant_port_db[1][1] << RESET; + msg << " -- SNR: " << std::left << std::setprecision(3) << std::setw(5) << ce_res->snr_db << RESET; + msg << RESET << " -- Result: "; if (result) { - std::cout << std::left << std::setw(8) << GREEN << "SUCCESS"; + msg << std::left << std::setw(8) << GREEN << "SUCCESS"; } else { - std::cout << std::left << std::setw(8) << RED << "FAILED"; + msg << std::left << std::setw(8) << RED << "FAILED"; } - std::cout << RESET << std::endl; -} + msg << RESET << std::endl; + if(DEBUG_DCI_PRINT==1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + (*filewriter_objs)[FILE_IDX_DL_DCI]->write_stats(msg.str()); + } +} // DL std::string PDSCH_Decoder::dci_format(int format) { @@ -1291,6 +1317,9 @@ std::string convert_id_name_dl(int id) case 3: ret = "IMSI"; break; + case 6: + ret = "Timing Advance"; + break; default: ret = "-"; break; @@ -1320,20 +1349,46 @@ std::string convert_msg_name_dl(int msg) case 5: ret = "Paging"; break; + case 6: + ret = "Random Access Response"; + break; default: ret = "-"; break; } return ret; } -void PDSCH_Decoder::print_api_dl(uint32_t tti, uint16_t rnti, int id, std::string value, int msg) +void PDSCH_Decoder::print_api_dl(uint32_t tti, uint16_t rnti, int id, std::string value, int msg, uint32_t ta_rnti) { - std::cout << std::left << std::setw(4) << tti / 10 << "-" << std::left << std::setw(5) << tti % 10; + std::stringstream msg_api; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg_api << "[" << cur_time_second << "]: "; + + msg_api << std::left << std::setw(4) << tti / 10 << "-" << std::left << std::setw(5) << tti % 10; std::string id_name = convert_id_name_dl(id); - std::cout << std::left << std::setw(26) << id_name; - std::cout << std::left << std::setw(17) << value; - std::cout << std::left << std::setw(11) << rnti; + msg_api << std::left << std::setw(26) << id_name; + msg_api << std::left << std::setw(17) << value; + msg_api << std::left << std::setw(11) << rnti; std::string msg_name = convert_msg_name_dl(msg); - std::cout << std::left << std::setw(25) << msg_name; - std::cout << std::endl; -} \ No newline at end of file + msg_api << std::left << std::setw(25) << msg_name; + if(ta_rnti!=-1){ + msg_api << std::left << std::setw(2) << "{" << ta_rnti << "}"; + } + msg_api << std::endl; + + if(DEBUG_SEC_PRINT==1){ + std::cout << msg_api.str(); + } + if(FILE_WRITE==1){ + (*filewriter_objs)[FILE_IDX_API]->write_stats(msg_api.str()); + } +} // DL \ No newline at end of file diff --git a/src/src/FileWriter.cc b/src/src/FileWriter.cc new file mode 100644 index 0000000..3a8ef62 --- /dev/null +++ b/src/src/FileWriter.cc @@ -0,0 +1,50 @@ +/* + * LTE DL_Snifer BWS addition + */ + +#include "include/FileWriter.h" + +void LTESniffer_stat_writer::enable(bool en) +{ + enable_write = true; +} +void LTESniffer_stat_writer::open(const std::string filename) +{ + fprintf(stdout, "Opening Statistic file\n"); + stat_file = fopen(filename.c_str(), "w"); + if (stat_file == NULL) { + printf("Failed to open file \"%s\" for writing\n", filename.c_str()); + } + enable_write = true; +} + +void LTESniffer_stat_writer::close() +{ + int err = -1; + if (stat_file) { + err = fclose(stat_file); + } + fprintf(stdout, "Closing Statistic file: success %d \n", err==0); +} + +// public method +void LTESniffer_stat_writer::write_stats(std::string stats) +{ + writer(stats); +} + +// private method +void LTESniffer_stat_writer::writer(std::string stats) +{ + std::unique_lock lock(stat_mutex); + if (enable_write) { + if (stat_file == NULL) { + /* Can't write if file wasn't successfully opened */ + printf("Error: Can't write to empty file handle\n"); + } else { + /* Now write everything to the file */ + fwrite(stats.data(), sizeof(char), stats.size(), stat_file); + } + } + lock.unlock(); +} \ No newline at end of file diff --git a/src/src/LTESniffer_Core.cc b/src/src/LTESniffer_Core.cc index e091341..ed3efcc 100644 --- a/src/src/LTESniffer_Core.cc +++ b/src/src/LTESniffer_Core.cc @@ -23,6 +23,10 @@ #include "srsran/common/gen_mch_tables.h" #include "srsran/phy/io/filesink.h" +#include "include/Sniffer_file_defs.h" +#include +#include + #ifdef __cplusplus } #undef I // Fix complex.h #define I nastiness when using C++ @@ -41,7 +45,15 @@ LTESniffer_Core::LTESniffer_Core(const Args& args): harq_mode(args.harq_mode), sniffer_mode(args.sniffer_mode), ulsche(args.target_rnti, &ul_harq, args.en_debug), - api_mode(args.api_mode) + api_mode(args.api_mode), + apiwriter(), // need to declare + dlwriter(), // need to declare + dldciwriter(), // need to declare + ulwriter(), // need to declare + uldciwriter(), // need to declare + rarwriter(), // need to declare + otherwriter(), // need to declare + filewriter_objs({&apiwriter, &dlwriter, &dldciwriter, &ulwriter, &uldciwriter, &rarwriter, &otherwriter}) // need pointers to persist { /*create pcap writer and name of output file*/ auto now = std::chrono::system_clock::now(); @@ -56,8 +68,22 @@ LTESniffer_Core::LTESniffer_Core(const Args& args): *it = '.'; } } - std::cout << str_cur_time << std::endl; - // std::string pcap_file_name = "ul_pcap_" + str_cur_time + "pcap"; + + std::string stat_folder = "/home/stats/"; + filewriter_objs[FILE_IDX_CONTROL]->open((stat_folder + "LETTUCE_control_" + str_cur_time + "ansi")); + std::stringstream control_msg_contruct; + + control_msg_contruct << "\nLTESniffer_Core: Starting...\n\n"; + control_msg_contruct << str_cur_time << std::endl; + + std::string mode_str = "NA"; + if(sniffer_mode==0){mode_str = "DL only";} + else if(sniffer_mode==1){mode_str = "UL only";} + else if(sniffer_mode==2){mode_str = "DL & UL";} + control_msg_contruct << "Sniffer Mode: " << mode_str << std::endl; + + // File Writers + // std::string pcap_file_name = "ul_pcap_" + str_cur_time + "pcap"; std::string pcap_file_name; std::string pcap_file_name_api = "api_collector.pcap"; if (sniffer_mode == DL_MODE){ @@ -66,10 +92,35 @@ LTESniffer_Core::LTESniffer_Core(const Args& args): pcap_file_name = "ltesniffer_ul_mode.pcap"; } pcapwriter.open(pcap_file_name, pcap_file_name_api, 0); + + struct stat st = {0}; + if (stat(stat_folder.c_str(), &st) == -1) { + mkdir(stat_folder.c_str(), 0700); + } + + std::string error_filename = stat_folder + "LETTUCE_stderr_" + str_cur_time + "ansi"; + errfile = freopen(error_filename.c_str(),"w",stderr); + + std::string out_filename = stat_folder + "LETTUCE_stdout_" + str_cur_time + "ansi"; + // this will do the same format on command line with tee + // date +"LETTUCE_stdout_%a_%b__%-d_%H.%M.%S_%Y.ansi" + // outfile = freopen(out_filename.c_str(),"w",stdout); + + filewriter_objs[FILE_IDX_API]->open((stat_folder + "LETTUCE_api_" + str_cur_time + "ansi")); + filewriter_objs[FILE_IDX_DL]->open((stat_folder + "LETTUCE_dl_tab_" + str_cur_time + "ansi")); + filewriter_objs[FILE_IDX_DL_DCI]->open((stat_folder + "LETTUCE_dl_dci_" + str_cur_time + "ansi")); + filewriter_objs[FILE_IDX_UL]->open((stat_folder + "LETTUCE_ul_tab_" + str_cur_time + "ansi")); + filewriter_objs[FILE_IDX_UL_DCI]->open((stat_folder + "LETTUCE_ul_dci_" + str_cur_time + "ansi")); + // filewriter_objs[FILE_IDX_RAR]->open((stat_folder + "LETTUCE_rar_" + str_cur_time + "ansi")); + /*Init HARQ*/ harq.init_HARQ(args.harq_mode); /*Set multi offset in ULSchedule*/ - ulsche.set_multi_offset(args.sniffer_mode); + int multi_offset_toggle = 0; + if((sniffer_mode == UL_MODE) || (sniffer_mode == DL_UL_MODE)) { + multi_offset_toggle = 1; + } + ulsche.set_multi_offset(multi_offset_toggle); /*Create PHY*/ phy = new Phy(args.rf_nof_rx_ant, args.nof_sniffer_thread, @@ -79,6 +130,7 @@ LTESniffer_Core::LTESniffer_Core(const Args& args): args.dci_format_split_ratio, args.rnti_histogram_threshold, &pcapwriter, + &filewriter_objs, &mcs_tracking, &harq, args.mcs_tracking_mode, @@ -102,6 +154,8 @@ LTESniffer_Core::LTESniffer_Core(const Args& args): for (int i = 0; i<100; i++){ ta_buffer.ta_last_sample[i] = 0; } + + write_file_and_console(control_msg_contruct.str(), filewriter_objs[FILE_IDX_CONTROL]); } bool LTESniffer_Core::run(){ @@ -116,6 +170,8 @@ bool LTESniffer_Core::run(){ srsran_pdsch_cfg_t pdsch_cfg; srsran_ue_sync_t ue_sync; + std::stringstream control_msg; + #ifndef DISABLE_RF srsran_rf_t rf; // to open RF devices #endif @@ -124,6 +180,7 @@ bool LTESniffer_Core::run(){ float search_cell_cfo = 0; // freg. offset uint32_t sfn = 0; // system frame number uint32_t skip_cnt = 0; // number of skipped subframe + uint32_t rx_fail_cnt = 0; // number of failed receive sample errors from UHD uint32_t total_sf = 0; uint32_t skip_last_1s = 0; uint16_t nof_lost_sync = 0; @@ -150,20 +207,24 @@ bool LTESniffer_Core::run(){ /* If RF mode (not file mode)*/ #ifndef DISABLE_RF if (args.input_file_name == "") { - printf("Opening RF device with %d RX antennas...\n", args.rf_nof_rx_ant); + //printf("Opening RF device with %d RX antennas...\n", args.rf_nof_rx_ant); + control_msg << "Opening RF device with " << args.rf_nof_rx_ant << " RX antennas...\n"; char rfArgsCStr[1024]; strncpy(rfArgsCStr, args.rf_args.c_str(), 1024); if (srsran_rf_open_multi(&rf, rfArgsCStr, args.rf_nof_rx_ant)) { fprintf(stderr, "Error opening rf\n"); + control_msg << "Error opening rf\n"; exit(-1); } /* Set receiver gain */ if (args.rf_gain > 0) { srsran_rf_set_rx_gain(&rf, args.rf_gain); } else { - printf("Starting AGC thread...\n"); + //printf("Starting AGC thread...\n"); + control_msg << "Starting AGC thread...\n"; if (srsran_rf_start_gain_thread(&rf, false)) { ERROR("Error opening rf"); + control_msg << "Error opening rf\n"; exit(-1); } srsran_rf_set_rx_gain(&rf, srsran_rf_get_rx_gain(&rf)); @@ -172,35 +233,62 @@ bool LTESniffer_Core::run(){ /* set receiver frequency */ if (sniffer_mode == UL_MODE && args.ul_freq != 0){ - printf("Tunning DL receiver to %.3f MHz\n", (args.rf_freq + args.file_offset_freq) / 1000000); + control_msg << "Tunning DL receiver to " << std::fixed << std::setprecision(3) << ((args.rf_freq + args.file_offset_freq) / 1000000) << std::endl; + //printf("Tunning DL receiver to %.3f MHz\n", (args.rf_freq + args.file_offset_freq) / 1000000); if (srsran_rf_set_rx_freq(&rf, 0, args.rf_freq + args.file_offset_freq)) { ///ERROR("Tunning DL Freq failed\n"); } /*Uplink freg*/ - printf("Tunning UL receiver to %.3f MHz\n", (double) (args.ul_freq / 1000000)); + control_msg << "Tunning UL receiver to " << std::fixed << std::setprecision(3) << ((double) (args.ul_freq / 1000000)) << std::endl; + //printf("Tunning UL receiver to %.3f MHz\n", (double) (args.ul_freq / 1000000)); if (srsran_rf_set_rx_freq(&rf, 1, args.ul_freq )){ //ERROR("Tunning UL Freq failed \n"); } } else if (sniffer_mode == UL_MODE && args.ul_freq == 0){ - ERROR("Uplink Frequency must be defined in the UL Sniffer Mode \n"); + control_msg << "Uplink Frequency must be defined in the UL Sniffer Mode \n"; + ERROR("Uplink Frequency must be defined in the UL Sniffer Mode"); } else if (sniffer_mode == DL_MODE && args.ul_freq == 0){ - printf("Tunning receiver to %.3f MHz\n", (args.rf_freq + args.file_offset_freq) / 1000000); + control_msg << "Tunning DL receiver to " << std::fixed << std::setprecision(3) << ((args.rf_freq + args.file_offset_freq) / 1000000) << std::endl; + //printf("Tunning receiver to %.3f MHz\n", (args.rf_freq + args.file_offset_freq) / 1000000); srsran_rf_set_rx_freq(&rf, args.rf_nof_rx_ant, args.rf_freq + args.file_offset_freq); } else if (sniffer_mode == DL_MODE && args.ul_freq != 0){ - ERROR("Uplink Frequency must be 0 in the DL Sniffer Mode \n"); + control_msg << "Uplink Frequency must be 0 in the DL Sniffer Mode \n"; + ERROR("Uplink Frequency must be 0 in the DL Sniffer Mode"); + } else if (sniffer_mode == DL_UL_MODE && args.ul_freq != 0){ + control_msg << "Tunning DL receiver to " << std::fixed << std::setprecision(3) << ((args.rf_freq + args.file_offset_freq) / 1000000) << std::endl; + //printf("Tunning DL receiver to %.3f MHz\n", (args.rf_freq + args.file_offset_freq) / 1000000); + if (srsran_rf_set_rx_freq(&rf, 0, args.rf_freq + args.file_offset_freq)) { + ///ERROR("Tunning DL Freq failed\n"); + } + /*Uplink freg*/ + control_msg << "Tunning UL receiver to " << std::fixed << std::setprecision(3) << ((double) (args.ul_freq / 1000000)) << std::endl; + //printf("Tunning UL receiver to %.3f MHz\n", (double) (args.ul_freq / 1000000)); + if (srsran_rf_set_rx_freq(&rf, 1, args.ul_freq )){ + //ERROR("Tunning UL Freq failed \n"); + } + } else if (sniffer_mode == DL_UL_MODE && args.ul_freq == 0){ + control_msg << "Uplink Frequency must be defined in the UL Sniffer Mode \n"; + ERROR("Uplink Frequency must be defined in the UL Sniffer Mode"); } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); if (args.cell_search){ uint32_t ntrial = 0; do { + control_msg << "Searching for cell...\n"; ret = rf_search_and_decode_mib( &rf, args.rf_nof_rx_ant, &cell_detect_config, args.force_N_id_2, &cell, &search_cell_cfo); if (ret < 0) { + control_msg << "Error searching for cell \n"; ERROR("Error searching for cell"); exit(-1); } else if (ret == 0 && !go_exit) { - printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); + control_msg << "Cell not found after " << ntrial++ << " trials. Trying again (Press Ctrl+C to exit)\n"; + //printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); } while (ret == 0 && !go_exit); } else{ //set up cell manually @@ -221,16 +309,21 @@ bool LTESniffer_Core::run(){ /* set sampling frequency */ int srate = srsran_sampling_freq_hz(cell.nof_prb); if (srate != -1) { - printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + control_msg << "Setting sampling rate " << std::fixed << std::setprecision(2) << ((float)srate / 1000000) << " MHz\n"; + //printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); float srate_rf = srsran_rf_set_rx_srate(&rf, (double)srate); if (srate_rf != srate) { + control_msg << "Could not set sampling rate\n"; ERROR("Could not set sampling rate"); exit(-1); } } else { + control_msg << "Invalid number of PRB " << cell.nof_prb << std::endl; ERROR("Invalid number of PRB %d", cell.nof_prb); exit(-1); } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); INFO("Stopping RF and flushing buffer...\r"); } @@ -255,7 +348,10 @@ bool LTESniffer_Core::run(){ args.file_offset_time, args.file_offset_freq, args.rf_nof_rx_ant)) { //args.rf_nof_rx_ant + control_msg << "Error initiating ue_sync" << std::endl; ERROR("Error initiating ue_sync"); + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); exit(-1); } delete[] tmp_filename; @@ -266,7 +362,10 @@ bool LTESniffer_Core::run(){ int decimate = 0; if (args.decimate) { if (args.decimate > 4 || args.decimate < 0) { - printf("Invalid decimation factor, setting to 1 \n"); + control_msg << "Invalid decimation factor, setting to 1 \n"; + //printf("Invalid decimation factor, setting to 1 \n"); + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); } else { decimate = args.decimate; } @@ -279,10 +378,16 @@ bool LTESniffer_Core::run(){ (void*)&rf, decimate)) { ERROR("Error initiating ue_sync"); + control_msg << "Error initiating ue_sync" << std::endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); exit(-1); } if (srsran_ue_sync_set_cell(&ue_sync, cell)) { ERROR("Error initiating ue_sync"); + control_msg << "Error initiating ue_sync" << std::endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); exit(-1); } #endif @@ -302,12 +407,18 @@ bool LTESniffer_Core::run(){ srsran_ue_mib_t ue_mib; if (srsran_ue_mib_init(&ue_mib, cur_buffer[0], cell.nof_prb)) { ERROR("Error initaiting UE MIB decoder"); + control_msg << "Error initaiting UE MIB decoder" << std::endl; exit(-1); } if (srsran_ue_mib_set_cell(&ue_mib, cell)) { ERROR("Error initaiting UE MIB decoder"); + control_msg << "Error initaiting UE MIB decoder" << std::endl; exit(-1); } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); + + srsran_sync_set_threshold(&ue_sync.sfind, 2.0); // Disable CP based CFO estimation during find ue_sync.cfo_current_value = search_cell_cfo / 15000; @@ -367,7 +478,17 @@ bool LTESniffer_Core::run(){ if (args.input_file_name != ""){ std::cout << "Finish reading from file" << std::endl; } - ERROR("Error calling srsran_ue_sync_work()"); + rx_fail_cnt++; + ERROR("Error calling srsran_ue_sync_work() cnt: %d", rx_fail_cnt); + control_msg << "Error calling srsran_ue_sync_work() cnt: " << to_string(rx_fail_cnt) << std::endl; + if(rx_fail_cnt>UHD_FAIL_LIMIT){ + control_msg << "EXITING because of UHD Error Limit Reached: " << to_string(UHD_FAIL_LIMIT) << std::endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); + return EXIT_FAILURE; + } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); } // std:: cout << "CFO = " << srsran_ue_sync_get_cfo(&ue_sync) << std::endl; #ifdef CORRECT_SAMPLE_OFFSET @@ -386,11 +507,18 @@ bool LTESniffer_Core::run(){ n = srsran_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); if (n < 0) { ERROR("Error decoding UE MIB"); + control_msg << "Error decoding UE MIB" << std::endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); exit(-1); } else if (n == SRSRAN_UE_MIB_FOUND) { srsran_pbch_mib_unpack(bch_payload, &cell, &sfn); - srsran_cell_fprint(stdout, &cell, sfn); - printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset); + cell_print(filewriter_objs[FILE_IDX_CONTROL], &cell, sfn); + //srsran_cell_fprint(stdout, &cell, sfn); + control_msg << "Decoded MIB. SFN: " << sfn << ", offset: " << sfn_offset << "\n"; + //printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset); + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); sfn = (sfn + sfn_offset) % 1024; state = DECODE_PDSCH; @@ -420,7 +548,8 @@ bool LTESniffer_Core::run(){ break; case DECODE_PDSCH: if ((mcs_tracking.get_nof_api_msg()%30) == 0 && api_mode > -1){ - print_api_header(); + print_api_header(filewriter_objs[FILE_IDX_API]); + //std::cout << std::hash{}(std::this_thread::get_id()) << std::endl; mcs_tracking.increase_nof_api_msg(); if (mcs_tracking.get_nof_api_msg() > 30){ mcs_tracking.reset_nof_api_msg(); @@ -460,17 +589,30 @@ bool LTESniffer_Core::run(){ sfn = 0; } total_sf++; - if ((total_sf%1000)==0 && (api_mode == -1)){ + + if ((total_sf%1000)==0){// && (api_mode == -1)){ auto now = std::chrono::system_clock::now(); std::time_t cur_time = std::chrono::system_clock::to_time_t(now); std::string str_cur_time(std::ctime(&cur_time)); - std::string cur_time_second = str_cur_time.substr(11,8); - std::cout << "[" << cur_time_second << "] Processed " << (1000 - skip_last_1s) << "/1000 subframes" << "\n"; + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + + control_msg << "[" << cur_time_second << "] Processed " << (1000 - skip_last_1s) << "/1000 subframes" << "\n"; + control_msg << "Skipped subframe: " << skip_cnt << " / " << sf_cnt << endl; + control_msg << "Skipped subframes: " << skip_cnt << " (" << static_cast(skip_cnt) * 100 / (phy->getCommon().getStats().nof_subframes + skip_cnt) << "%)" << endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); + mcs_tracking_timer++; update_rnti_timer ++; skip_last_1s = 0; } if (update_rnti_timer == mcs_tracking.get_interval()){ + //std::cout << "update tables" << std::endl; switch (sniffer_mode) { case DL_MODE: @@ -479,6 +621,12 @@ bool LTESniffer_Core::run(){ case UL_MODE: if (mcs_tracking_mode){ mcs_tracking.update_database_ul(); } break; + case DL_UL_MODE: + // Downlink + if (mcs_tracking_mode && args.target_rnti == 0){ mcs_tracking.update_database_dl(); } + // Uplink + if (mcs_tracking_mode){ mcs_tracking.update_database_ul(); } + break; default: break; } @@ -486,16 +634,27 @@ bool LTESniffer_Core::run(){ } /* Update 256tracking and harq database, delete the inactive RNTIs*/ if (mcs_tracking_timer == 10){ + //std::cout << "print tables" << std::endl; switch (sniffer_mode) { case DL_MODE: - if (api_mode == -1) {mcs_tracking.print_database_dl();} + mcs_tracking.print_database_dl(filewriter_objs[FILE_IDX_DL], api_mode); if (mcs_tracking_mode && args.target_rnti == 0){ mcs_tracking.update_database_dl(); } if (harq_mode && args.target_rnti == 0){ harq.updateHARQDatabase(); } mcs_tracking_timer = 0; break; case UL_MODE: - if (api_mode == -1) {mcs_tracking.print_database_ul();} + mcs_tracking.print_database_ul(filewriter_objs[FILE_IDX_UL], api_mode); + if (mcs_tracking_mode){ mcs_tracking.update_database_ul(); } + mcs_tracking_timer = 0; + break; + case DL_UL_MODE: + // Downlink + mcs_tracking.print_database_dl(filewriter_objs[FILE_IDX_DL], 1); // force DL to not print in DL/UL mode + if (mcs_tracking_mode && args.target_rnti == 0){ mcs_tracking.update_database_dl(); } + if (harq_mode && args.target_rnti == 0){ harq.updateHARQDatabase(); } + // Uplink + mcs_tracking.print_database_ul(filewriter_objs[FILE_IDX_UL], api_mode); if (mcs_tracking_mode){ mcs_tracking.update_database_ul(); } mcs_tracking_timer = 0; break; @@ -504,24 +663,40 @@ bool LTESniffer_Core::run(){ } } } else if(ret == 0){ //get buffer wrong or out of sync + //std::cout << "issues" << std::endl; /*Change state to Decode MIB to find system frame number again*/ if (state == DECODE_PDSCH && nof_lost_sync > 5){ state = DECODE_MIB; if (srsran_ue_mib_init(&ue_mib, cur_worker->getBuffers()[0], cell.nof_prb)) { ERROR("Error initaiting UE MIB decoder"); + control_msg << "Error initaiting UE MIB decoder" << std::endl; exit(-1); } if (srsran_ue_mib_set_cell(&ue_mib, cell)) { + control_msg << "Error initaiting UE MIB decoder" << std::endl; ERROR("Error initaiting UE MIB decoder"); exit(-1); } + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); srsran_pbch_decode_reset(&ue_mib.pbch); nof_lost_sync = 0; } + + if(srsran_sync_get_peak_value(&ue_sync.sfind) > srsran_sync_get_threshold(&ue_sync.sfind)){ + control_msg << "Found PSS... NID2: " << cell.id % 3 << + ", Peak: " << srsran_sync_get_peak_value(&ue_sync.sfind) << + ", Threshold: " << srsran_sync_get_threshold(&ue_sync.sfind) << + ", FrameCnt: " << ue_sync.frame_total_cnt << + " State: " << ue_sync.state << endl; + control_msg << "Missed PSS Attempts: " << nof_lost_sync << endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); + } nof_lost_sync++; - cout << "Finding PSS... Peak: " << srsran_sync_get_peak_value(&ue_sync.sfind) << - ", FrameCnt: " << ue_sync.frame_total_cnt << - " State: " << ue_sync.state << endl; + // cout << "Finding PSS... Peak: " << srsran_sync_get_peak_value(&ue_sync.sfind) << + // ", FrameCnt: " << ue_sync.frame_total_cnt << + // " State: " << ue_sync.state << endl; } sf_cnt++; @@ -533,11 +708,19 @@ bool LTESniffer_Core::run(){ { case DL_MODE: mcs_tracking.merge_all_database_dl(); - if (api_mode == -1) {mcs_tracking.print_all_database_dl(); } + mcs_tracking.print_all_database_dl(filewriter_objs[FILE_IDX_DL], api_mode); break; case UL_MODE: mcs_tracking.merge_all_database_ul(); - if (api_mode == -1) {mcs_tracking.print_all_database_ul(); } + mcs_tracking.print_all_database_ul(filewriter_objs[FILE_IDX_UL], api_mode); + break; + case DL_UL_MODE: + // Downlink + mcs_tracking.merge_all_database_dl(); + mcs_tracking.print_all_database_dl(filewriter_objs[FILE_IDX_DL], api_mode); // allow final DL table in DL/UL mode + // Uplink + mcs_tracking.merge_all_database_ul(); + mcs_tracking.print_all_database_ul(filewriter_objs[FILE_IDX_UL], api_mode); break; default: break; @@ -546,7 +729,7 @@ bool LTESniffer_Core::run(){ phy->joinPending(); - std::cout << "Destroyed Phy" << std::endl; + control_msg << "Destroyed Phy" << std::endl; if (args.input_file_name == ""){ srsran_rf_close(&rf); //srsran_ue_dl_free(falcon_ue_dl.q); @@ -554,13 +737,16 @@ bool LTESniffer_Core::run(){ srsran_ue_mib_free(&ue_mib); } //common->getRNTIManager().printActiveSet(); - cout << "Skipped subframe: " << skip_cnt << " / " << sf_cnt << endl; + control_msg << "Skipped subframe: " << skip_cnt << " / " << sf_cnt << endl; //phy->getCommon().getRNTIManager().printActiveSet(); //rnti_manager_print_active_set(falcon_ue_dl.rnti_manager); phy->getCommon().printStats(); - cout << "Skipped subframes: " << skip_cnt << " (" << static_cast(skip_cnt) * 100 / (phy->getCommon().getStats().nof_subframes + skip_cnt) << "%)" << endl; + control_msg << "Skipped subframes: " << skip_cnt << " (" << static_cast(skip_cnt) * 100 / (phy->getCommon().getStats().nof_subframes + skip_cnt) << "%)" << endl; + write_file_and_console(control_msg.str(), filewriter_objs[FILE_IDX_CONTROL]); + control_msg.str(std::string()); + /* Print statistic of 256tracking*/ // if (mcs_tracking_mode){ mcs_tracking.print_database_ul(); } @@ -570,7 +756,8 @@ bool LTESniffer_Core::run(){ } void LTESniffer_Core::stop() { - cout << "LTESniffer_Core: Exiting..." << endl; + std::string mystring = "\nLTESniffer_Core: Exiting...\n"; + write_file_and_console(mystring, filewriter_objs[FILE_IDX_CONTROL]); go_exit = true; } @@ -580,6 +767,17 @@ void LTESniffer_Core::handleSignal() { LTESniffer_Core::~LTESniffer_Core(){ pcapwriter.close(); + errfile = freopen("/dev/tty","r",stderr); + fclose (stderr); + //outfile = freopen("/dev/tty","r",stdout); + //fclose (stdout); + filewriter_objs[FILE_IDX_API]->close(); + filewriter_objs[FILE_IDX_DL]->close(); + filewriter_objs[FILE_IDX_DL_DCI]->close(); + filewriter_objs[FILE_IDX_UL]->close(); + filewriter_objs[FILE_IDX_UL_DCI]->close(); + //filewriter_objs[FILE_IDX_RAR]->close(); + filewriter_objs[FILE_IDX_CONTROL]->close(); // delete harq_map; // harq_map = nullptr; // delete phy; @@ -620,19 +818,76 @@ void LTESniffer_Core::setRNTIThreshold(int val){ if(phy){phy->getCommon().getRNTIManager().setHistogramThreshold(val);} } -void LTESniffer_Core::print_api_header(){ +void LTESniffer_Core::print_api_header(LTESniffer_stat_writer *filewriter_obj){ + std::stringstream msg_api; + for (int i = 0; i < 90; i++){ - std::cout << "-"; + msg_api << "-"; } - std::cout << std::endl; - std::cout << std::left << std::setw(10) << "SF"; - std::cout << std::left << std::setw(26) << "Detected Identity"; - std::cout << std::left << std::setw(17) << "Value"; - std::cout << std::left << std::setw(11) << "RNTI"; - std::cout << std::left << std::setw(25) << "From Message"; - std::cout << std::endl; + msg_api << std::endl; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg_api << "[" << cur_time_second << "]: "; + + msg_api << std::left << std::setw(10) << "SF"; + msg_api << std::left << std::setw(26) << "Detected Identity"; + msg_api << std::left << std::setw(17) << "Value"; + msg_api << std::left << std::setw(11) << "RNTI"; + msg_api << std::left << std::setw(25) << "From Message"; + msg_api << std::endl; for (int i = 0; i < 90; i++){ - std::cout << "-"; + msg_api << "-"; } - std::cout << std::endl; + msg_api << std::endl; + + if(DEBUG_SEC_PRINT==1){ + std::cout << msg_api.str(); + } + if(FILE_WRITE==1){ + filewriter_obj->write_stats(msg_api.str()); + } } + +void write_file_and_console(std::string mystring, LTESniffer_stat_writer* filewriter_obj){ + filewriter_obj->write_stats(mystring); + std::cout << mystring; +} + +void cell_print(LTESniffer_stat_writer* filewriter_obj, srsran_cell_t* cell, uint32_t sfn) +{ + std:string mystring = ""; + mystring = mystring + " - Type: " + (cell->frame_type == SRSRAN_FDD ? "FDD" : "TDD") + "\n"; + mystring = mystring + " - PCI: " + std::to_string(cell->id) + "\n"; + mystring = mystring + " - Nof ports: " + std::to_string(cell->nof_ports) + "\n"; + mystring = mystring + " - CP: " + (srsran_cp_string(cell->cp)) + "\n"; + mystring = mystring + " - PRB: " + std::to_string(cell->nof_prb) + "\n"; + mystring = mystring + " - PHICH Length: " + (cell->phich_length == SRSRAN_PHICH_EXT ? "Extended" : "Normal") + "\n"; + mystring = mystring + " - PHICH Resources: "; + switch (cell->phich_resources) { + case SRSRAN_PHICH_R_1_6: + mystring = mystring + "1/6"; + break; + case SRSRAN_PHICH_R_1_2: + mystring = mystring + "1/2"; + break; + case SRSRAN_PHICH_R_1: + mystring = mystring + "1"; + break; + case SRSRAN_PHICH_R_2: + mystring = mystring + "2"; + break; + } + mystring = mystring + "\n"; + mystring = mystring + " - SFN: " + std::to_string(sfn) + "\n"; + + filewriter_obj->write_stats(mystring); + std::cout << mystring; +} \ No newline at end of file diff --git a/src/src/MCSTracking.cc b/src/src/MCSTracking.cc index b36ebd2..acff7b2 100644 --- a/src/src/MCSTracking.cc +++ b/src/src/MCSTracking.cc @@ -32,7 +32,7 @@ MCSTracking::~MCSTracking() ul_sniffer_mod_tracking_t MCSTracking::find_tracking_info_RNTI_ul(uint16_t RNTI) { - std::unique_lock trackinglock(tracking_mutex); + std::lock_guard trackinglock(tracking_mutex); std::map::iterator iter; iter = tracking_database_ul_mode.find(RNTI); if ((nof_RNTI_member_ul() == 0) || (iter == tracking_database_ul_mode.end())) @@ -53,7 +53,6 @@ ul_sniffer_mod_tracking_t MCSTracking::find_tracking_info_RNTI_ul(uint16_t RNTI) iter->second.time = cur_time; return iter->second.mcs_mod; } - trackinglock.unlock(); } int MCSTracking::add_RNTI_ul(uint16_t RNTI, ul_sniffer_mod_tracking_t mcs_mod) @@ -238,13 +237,14 @@ void MCSTracking::merge_all_database_ul() trackinglock.unlock(); } -void print_statistic_rnti_ul_mode(std::map::iterator iter, int num, std::string info) +void print_statistic_rnti_ul_mode(std::stringstream &msg, std::map::iterator iter, int num, std::string info) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << info; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << std::left << std::setw(9) << iter->second.nof_success_mgs; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << info; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << std::left << std::setw(9) << iter->second.nof_success_mgs; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -255,7 +255,7 @@ void print_statistic_rnti_ul_mode(std::map::ite } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -270,35 +270,49 @@ void print_statistic_rnti_ul_mode(std::map::ite } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; } -void print_header_ul_mode() +void print_header_ul_mode(std::stringstream &msg) { - std::cout << std::left << std::setw(5) << "Num"; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Max Mod"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << std::left << std::setw(9) << "Success"; - std::cout << std::left << std::setw(9) << "SNR(dB)"; - std::cout << std::left << std::setw(18) << "DL-UL_delay(us)"; - std::cout << std::left << std::setw(9) << "Other_Info"; - std::cout << std::endl; + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(5) << "Num"; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Max Mod"; + msg << std::left << std::setw(9) << "Active"; + msg << std::left << std::setw(9) << "Success"; + msg << std::left << std::setw(9) << "SNR(dB)"; + msg << std::left << std::setw(18) << "DL-UL_delay(us)"; + msg << std::left << std::setw(9) << "Other_Info"; + msg << std::endl; } -void MCSTracking::print_database_ul() +void MCSTracking::print_database_ul(LTESniffer_stat_writer *filewriter_obj, int api_mode) { std::unique_lock trackinglock(tracking_mutex); std::map::iterator iter; + + std::stringstream msg; + int nof_16qam = 0; int nof_64qam = 0; int nof_256qam = 0; @@ -307,23 +321,23 @@ void MCSTracking::print_database_ul() for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; - print_header_ul_mode(); + print_header_ul_mode(msg); for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = tracking_database_ul_mode.begin(); iter != tracking_database_ul_mode.end(); iter++) { if (iter->second.mcs_mod == UL_SNIFFER_16QAM_MAX && iter->second.nof_active > 0) { - print_statistic_rnti_ul_mode(iter, num, "16QAM"); + print_statistic_rnti_ul_mode(msg, iter, num, "16QAM"); nof_16qam++; num++; } @@ -332,7 +346,7 @@ void MCSTracking::print_database_ul() { if (iter->second.mcs_mod == UL_SNIFFER_64QAM_MAX && iter->second.nof_active > 0) { - print_statistic_rnti_ul_mode(iter, num, "64QAM"); + print_statistic_rnti_ul_mode(msg, iter, num, "64QAM"); nof_64qam++; num++; } @@ -341,18 +355,18 @@ void MCSTracking::print_database_ul() { if (iter->second.mcs_mod == UL_SNIFFER_256QAM_MAX && iter->second.nof_active > 0) { - print_statistic_rnti_ul_mode(iter, num, "256QAM"); + print_statistic_rnti_ul_mode(msg, iter, num, "256QAM"); nof_256qam++; num++; } } for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; - print_header_ul_mode(); + print_header_ul_mode(msg); for (iter = tracking_database_ul_mode.begin(); iter != tracking_database_ul_mode.end(); iter++) { @@ -360,7 +374,7 @@ void MCSTracking::print_database_ul() { if ((iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0 && iter->second.nof_active > 0)) { - print_statistic_rnti_ul_mode(iter, num, "Unknown"); + print_statistic_rnti_ul_mode(msg, iter, num, "Unknown"); nof_unknown++; num++; } @@ -369,9 +383,9 @@ void MCSTracking::print_database_ul() for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = tracking_database_ul_mode.begin(); iter != tracking_database_ul_mode.end(); iter++) { @@ -379,21 +393,40 @@ void MCSTracking::print_database_ul() { if ((iter->second.nof_active > 0) && !(iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0)) { - print_statistic_rnti_ul_mode(iter, num, "Unknown"); + print_statistic_rnti_ul_mode(msg, iter, num, "Unknown"); nof_unknown++; num++; } } } - printf("[256Tracking] Total: %d RNTIs are max 16QAM, %d RNTIs are max 64QAM table, %d RNTIs are max 256QAM, %d RNTIs are Unknown \n\n", - nof_16qam, nof_64qam, nof_256qam, nof_unknown); + + msg << "[256Tracking] Total: "; + msg << std::right << std::setw(6) << nof_64qam; + msg << " RNTIs are 64QAM table, "; + msg << std::right << std::setw(6) << nof_256qam; + msg << " RNTIs are 256QAM table, "; + msg << std::right << std::setw(6) << nof_unknown; + msg << " RNTIs are Unknown "; + msg << std::endl; + msg << std::endl; + + if(DEBUG_TABLE_PRINT==1 && api_mode == -1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + filewriter_obj->write_stats(msg.str()); + } + trackinglock.unlock(); } -void MCSTracking::print_all_database_ul() +void MCSTracking::print_all_database_ul(LTESniffer_stat_writer *filewriter_obj, int api_mode) { std::unique_lock trackinglock(tracking_mutex); std::map::iterator iter; + + std::stringstream msg; + int nof_16qam = 0; int nof_64qam = 0; int nof_256qam = 0; @@ -402,42 +435,54 @@ void MCSTracking::print_all_database_ul() for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; + } + msg << std::endl; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; } - std::cout << std::endl; + msg << "[" << cur_time_second << "]: "; - std::cout << std::left << std::setw(5) << "Num"; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Max Mod"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; - std::cout << std::left << std::setw(9) << "SNR(dB)"; - std::cout << std::left << std::setw(18) << "DL-UL_delay(us)"; - std::cout << std::left << std::setw(9) << "Other_Info"; - std::cout << std::endl; + msg << std::left << std::setw(5) << "Num"; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Max Mod"; + msg << std::left << std::setw(9) << "Active"; + msg << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; + msg << std::left << std::setw(9) << "SNR(dB)"; + msg << std::left << std::setw(18) << "DL-UL_delay(us)"; + msg << std::left << std::setw(9) << "Other_Info"; + msg << std::endl; for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = all_database_ul_mode.begin(); iter != all_database_ul_mode.end(); iter++) { if (iter->second.mcs_mod == UL_SNIFFER_16QAM_MAX && iter->second.nof_active > 0) { nof_16qam++; - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "16QAM"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "16QAM"; + msg << std::left << std::setw(9) << iter->second.nof_active; int sc_percent = 0; if (iter->second.nof_active > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -448,7 +493,7 @@ void MCSTracking::print_all_database_ul() } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -463,15 +508,15 @@ void MCSTracking::print_all_database_ul() } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; num++; // write_csv_file(iter->first, iter->second, iter->second.mcs_mod); } @@ -481,17 +526,18 @@ void MCSTracking::print_all_database_ul() if (iter->second.mcs_mod == UL_SNIFFER_64QAM_MAX && iter->second.nof_active > 0) { nof_64qam++; - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "64QAM"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "64QAM"; + msg << std::left << std::setw(9) << iter->second.nof_active; int sc_percent = 0; if (iter->second.nof_active > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -502,7 +548,7 @@ void MCSTracking::print_all_database_ul() } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -517,15 +563,15 @@ void MCSTracking::print_all_database_ul() } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; num++; // write_csv_file(iter->first, iter->second, iter->second.mcs_mod); } @@ -534,17 +580,18 @@ void MCSTracking::print_all_database_ul() { if (iter->second.mcs_mod == UL_SNIFFER_256QAM_MAX && iter->second.nof_active > 0) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "256QAM"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "256QAM"; + msg << std::left << std::setw(9) << iter->second.nof_active; int sc_percent = 0; if (iter->second.nof_active > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -555,7 +602,7 @@ void MCSTracking::print_all_database_ul() } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -570,15 +617,15 @@ void MCSTracking::print_all_database_ul() } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_256qam++; num++; // write_csv_file(iter->first, iter->second, iter->second.mcs_mod); @@ -586,19 +633,21 @@ void MCSTracking::print_all_database_ul() } for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; + + msg << "[" << cur_time_second << "]: "; - std::cout << std::left << std::setw(5) << "Num "; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Max Mod"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; - std::cout << std::left << std::setw(9) << "SNR(dB)"; - std::cout << std::left << std::setw(18) << "DL-UL_delay(us)"; - std::cout << std::left << std::setw(9) << "Other_Info"; - std::cout << std::endl; + msg << std::left << std::setw(5) << "Num "; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Max Mod"; + msg << std::left << std::setw(9) << "Active"; + msg << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; + msg << std::left << std::setw(9) << "SNR(dB)"; + msg << std::left << std::setw(18) << "DL-UL_delay(us)"; + msg << std::left << std::setw(9) << "Other_Info"; + msg << std::endl; for (iter = all_database_ul_mode.begin(); iter != all_database_ul_mode.end(); iter++) { @@ -606,17 +655,18 @@ void MCSTracking::print_all_database_ul() { if ((iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0)) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "Unknown"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "Unknown"; + msg << std::left << std::setw(9) << iter->second.nof_active; int sc_percent = 0; if (iter->second.nof_active > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -627,7 +677,7 @@ void MCSTracking::print_all_database_ul() } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -642,15 +692,15 @@ void MCSTracking::print_all_database_ul() } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_unknown++; num++; // write_csv_file(iter->first, iter->second, iter->second.mcs_mod); @@ -660,9 +710,9 @@ void MCSTracking::print_all_database_ul() for (int i = 0; i < 86; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = all_database_ul_mode.begin(); iter != all_database_ul_mode.end(); iter++) { @@ -670,17 +720,18 @@ void MCSTracking::print_all_database_ul() { if (!(iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0)) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "Unknown"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "Unknown"; + msg << std::left << std::setw(9) << iter->second.nof_active; int sc_percent = 0; if (iter->second.nof_newtx > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; float sum_snr = 0; float ave_snr = 0; if (iter->second.snr.size() > 0) @@ -691,7 +742,7 @@ void MCSTracking::print_all_database_ul() } ave_snr = sum_snr / iter->second.snr.size(); } - std::cout << std::left << std::setw(9) << std::setprecision(3) << ave_snr; + msg << std::left << std::setw(9) << std::setprecision(3) << ave_snr; // iter->second.snr.clear(); /*TA*/ float sum_ta = 0; @@ -706,25 +757,40 @@ void MCSTracking::print_all_database_ul() } if (ave_ta >= 0) { - std::cout << "+"; - std::cout << std::left << std::setw(17) << std::setprecision(3) << ave_ta; + msg << "+"; + msg << std::left << std::setw(17) << std::setprecision(3) << ave_ta; } else { - std::cout << std::left << std::setw(18) << std::setprecision(3) << ave_ta; + msg << std::left << std::setw(18) << std::setprecision(3) << ave_ta; } - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_unknown++; num++; } } } - printf("[256Tracking] Total: %d RNTIs are max 16QAM table, %d RNTIs are max 64QAM table, %d RNTIs are max 256QAM, %d RNTIs are Unknown \n\n", - nof_16qam, nof_64qam, nof_256qam, nof_unknown); + + msg << "[256Tracking] Total: "; + msg << std::right << std::setw(6) << nof_64qam; + msg << " RNTIs are 64QAM table, "; + msg << std::right << std::setw(6) << nof_256qam; + msg << " RNTIs are 256QAM table, "; + msg << std::right << std::setw(6) << nof_unknown; + msg << " RNTIs are Unknown "; + msg << std::endl; + msg << std::endl; + + if(DEBUG_TABLE_PRINT==1 && api_mode == -1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + filewriter_obj->write_stats(msg.str()); + } trackinglock.unlock(); -} +} // print_all_database_ul void MCSTracking::update_statistic_ul(uint16_t RNTI, bool success, @@ -758,7 +824,7 @@ void MCSTracking::update_statistic_ul(uint16_t RNTI, dl_sniffer_mcs_table_t MCSTracking::find_tracking_info_RNTI_dl(uint16_t RNTI) { - std::unique_lock trackinglock(tracking_mutex); + std::lock_guard trackinglock(tracking_mutex); std::map::iterator iter; iter = tracking_database_dl_mode.find(RNTI); if ((nof_RNTI_member_dl() == 0) || (iter == tracking_database_dl_mode.end())) @@ -779,7 +845,6 @@ dl_sniffer_mcs_table_t MCSTracking::find_tracking_info_RNTI_dl(uint16_t RNTI) iter->second.time = cur_time; return iter->second.mcs_table; } - trackinglock.unlock(); } int MCSTracking::add_RNTI_dl(uint16_t RNTI, dl_sniffer_mcs_table_t mcs_table) @@ -962,44 +1027,59 @@ void MCSTracking::merge_all_database_dl() trackinglock.unlock(); } -void print_statistic_rnti(std::map::iterator iter, int num, std::string info) +void print_statistic_rnti(std::stringstream &msg,std::map::iterator iter, int num, std::string info) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << info; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << std::left << std::setw(9) << iter->second.nof_newtx; - std::cout << std::left << std::setw(9) << iter->second.nof_retx; - std::cout << std::left << std::setw(9) << iter->second.nof_success_mgs; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_harq; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_nom; - std::cout << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; - std::cout << std::left << std::setw(9) << iter->second.nof_pinfo; - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << info; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << std::left << std::setw(9) << iter->second.nof_newtx; + msg << std::left << std::setw(9) << iter->second.nof_retx; + msg << std::left << std::setw(9) << iter->second.nof_success_mgs; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_harq; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_nom; + msg << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; + msg << std::left << std::setw(9) << iter->second.nof_pinfo; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; } -void print_header() +void print_header(std::stringstream &msg) { - std::cout << std::left << std::setw(5) << "Num"; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Table"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << std::left << std::setw(9) << "New TX"; - std::cout << std::left << std::setw(9) << "ReTX"; - std::cout << std::left << std::setw(9) << "Success"; - std::cout << std::left << std::setw(9) << "HARQ"; - std::cout << std::left << std::setw(9) << "Normal"; - std::cout << std::left << std::setw(9) << "W_MIMO"; - std::cout << std::left << std::setw(9) << "W_pinfor"; - std::cout << std::left << std::setw(9) << "Other "; - std::cout << std::endl; + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(5) << "Num"; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Table"; + msg << std::left << std::setw(9) << "Active"; + msg << std::left << std::setw(9) << "New TX"; + msg << std::left << std::setw(9) << "ReTX"; + msg << std::left << std::setw(9) << "Success"; + msg << std::left << std::setw(9) << "HARQ"; + msg << std::left << std::setw(9) << "Normal"; + msg << std::left << std::setw(9) << "W_MIMO"; + msg << std::left << std::setw(9) << "W_pinfor"; + msg << std::left << std::setw(9) << "Other "; + msg << std::endl; } -void MCSTracking::print_database_dl() +void MCSTracking::print_database_dl(LTESniffer_stat_writer *filewriter_obj, int api_mode) { std::unique_lock trackinglock(tracking_mutex); std::map::iterator iter; + + std::stringstream msg; + int nof_64qam = 0; int nof_256qam = 0; int nof_unknown = 0; @@ -1007,23 +1087,23 @@ void MCSTracking::print_database_dl() for (int i = 0; i < 104; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; - print_header(); + print_header(msg); for (int i = 0; i < 104; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = tracking_database_dl_mode.begin(); iter != tracking_database_dl_mode.end(); iter++) { if (iter->second.mcs_table == DL_SNIFFER_64QAM_TABLE) { nof_64qam++; - print_statistic_rnti(iter, num, "64QAM"); + print_statistic_rnti(msg, iter, num, "64QAM"); num++; } } @@ -1031,18 +1111,18 @@ void MCSTracking::print_database_dl() { if (iter->second.mcs_table == DL_SNIFFER_256QAM_TABLE) { - print_statistic_rnti(iter, num, "256QAM"); + print_statistic_rnti(msg, iter, num, "256QAM"); nof_256qam++; num++; } } for (int i = 0; i < 104; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; - print_header(); + print_header(msg); for (iter = tracking_database_dl_mode.begin(); iter != tracking_database_dl_mode.end(); iter++) { if (iter->second.mcs_table == DL_SNIFFER_UNKNOWN_TABLE) @@ -1050,7 +1130,7 @@ void MCSTracking::print_database_dl() /*iter->second.nof_active > 0: some RNTIs have nof_active = 0 due to only obatained from rar message only, no other actives*/ if ((iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0 && iter->second.nof_active > 0)) { - print_statistic_rnti(iter, num, "Unknown"); + print_statistic_rnti(msg, iter, num, "Unknown"); nof_unknown++; num++; } @@ -1059,9 +1139,9 @@ void MCSTracking::print_database_dl() for (int i = 0; i < 104; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = tracking_database_dl_mode.begin(); iter != tracking_database_dl_mode.end(); iter++) { @@ -1070,21 +1150,40 @@ void MCSTracking::print_database_dl() /*iter->second.nof_active > 0: some RNTIs have nof_active = 0 due to only obatained from rar message only, no other actives*/ if (!(iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0) && iter->second.nof_active > 0) { - print_statistic_rnti(iter, num, "Unknown"); + print_statistic_rnti(msg, iter, num, "Unknown"); nof_unknown++; num++; } } } - printf("[256Tracking] Total: %d RNTIs are 64QAM table, %d RNTIs are 256QAM table, %d RNTIs are Unknown \n\n", - nof_64qam, nof_256qam, nof_unknown); + + msg << "[256Tracking] Total: "; + msg << std::right << std::setw(6) << nof_64qam; + msg << " RNTIs are 64QAM table, "; + msg << std::right << std::setw(6) << nof_256qam; + msg << " RNTIs are 256QAM table, "; + msg << std::right << std::setw(6) << nof_unknown; + msg << " RNTIs are Unknown "; + msg << std::endl; + msg << std::endl; + + if(DEBUG_TABLE_PRINT==1 && api_mode == -1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + filewriter_obj->write_stats(msg.str()); + } + trackinglock.unlock(); -} +} // print_database_dl -void MCSTracking::print_all_database_dl() +void MCSTracking::print_all_database_dl(LTESniffer_stat_writer *filewriter_obj, int api_mode) { std::unique_lock trackinglock(tracking_mutex); std::map::iterator iter; + + std::stringstream msg; + int nof_64qam = 0; int nof_256qam = 0; int nof_unknown = 0; @@ -1092,54 +1191,66 @@ void MCSTracking::print_all_database_dl() for (int i = 0; i < 109; i++) { - std::cout << "-"; - } - std::cout << std::endl; - - std::cout << std::left << std::setw(5) << "Num"; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Table"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << RED << std::left << std::setw(9) << "New TX" << RESET; - std::cout << std::left << std::setw(9) << "ReTX"; - std::cout << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; - std::cout << std::left << std::setw(9) << "HARQ"; - std::cout << std::left << std::setw(9) << "Normal"; - std::cout << std::left << std::setw(9) << "W_MIMO"; - std::cout << std::left << std::setw(9) << "W_pinfor"; - std::cout << std::left << std::setw(9) << "Other "; - std::cout << std::endl; + msg << "-"; + } + msg << std::endl; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(5) << "Num"; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Table"; + msg << std::left << std::setw(9) << "Active"; + msg << RED << std::left << std::setw(9) << "New TX" << RESET; + msg << std::left << std::setw(9) << "ReTX"; + msg << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; + msg << std::left << std::setw(9) << "HARQ"; + msg << std::left << std::setw(9) << "Normal"; + msg << std::left << std::setw(9) << "W_MIMO"; + msg << std::left << std::setw(9) << "W_pinfor"; + msg << std::left << std::setw(9) << "Other "; + msg << std::endl; for (int i = 0; i < 109; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = all_database_dl_mode.begin(); iter != all_database_dl_mode.end(); iter++) { if (iter->second.mcs_table == DL_SNIFFER_64QAM_TABLE) { nof_64qam++; - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "64QAM"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_retx; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "64QAM"; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; + msg << std::left << std::setw(9) << iter->second.nof_retx; int sc_percent = 0; if (iter->second.nof_newtx > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_harq; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_nom; - std::cout << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; - std::cout << std::left << std::setw(9) << iter->second.nof_pinfo; - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_harq; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_nom; + msg << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; + msg << std::left << std::setw(9) << iter->second.nof_pinfo; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; num++; write_csv_file(iter->first, iter->second, iter->second.mcs_table); } @@ -1148,25 +1259,26 @@ void MCSTracking::print_all_database_dl() { if (iter->second.mcs_table == DL_SNIFFER_256QAM_TABLE) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "256QAM"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_retx; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "256QAM"; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; + msg << std::left << std::setw(9) << iter->second.nof_retx; int sc_percent = 0; if (iter->second.nof_newtx > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_harq; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_nom; - std::cout << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; - std::cout << std::left << std::setw(9) << iter->second.nof_pinfo; - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_harq; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_nom; + msg << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; + msg << std::left << std::setw(9) << iter->second.nof_pinfo; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_256qam++; num++; write_csv_file(iter->first, iter->second, iter->second.mcs_table); @@ -1174,23 +1286,25 @@ void MCSTracking::print_all_database_dl() } for (int i = 0; i < 109; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; - std::cout << std::left << std::setw(5) << "Num "; - std::cout << std::left << std::setw(9) << "RNTI"; - std::cout << std::left << std::setw(12) << "Table"; - std::cout << std::left << std::setw(9) << "Active"; - std::cout << RED << std::left << std::setw(9) << "New TX" << RESET; - std::cout << std::left << std::setw(9) << "ReTX"; - std::cout << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; - std::cout << std::left << std::setw(9) << "HARQ"; - std::cout << std::left << std::setw(9) << "Normal"; - std::cout << std::left << std::setw(9) << "W_MIMO"; - std::cout << std::left << std::setw(9) << "W_pinfor"; - std::cout << std::left << std::setw(9) << "Other"; - std::cout << std::endl; + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(5) << "Num "; + msg << std::left << std::setw(9) << "RNTI"; + msg << std::left << std::setw(12) << "Table"; + msg << std::left << std::setw(9) << "Active"; + msg << RED << std::left << std::setw(9) << "New TX" << RESET; + msg << std::left << std::setw(9) << "ReTX"; + msg << BOLDGREEN << std::left << std::setw(13) << "Success" << RESET; + msg << std::left << std::setw(9) << "HARQ"; + msg << std::left << std::setw(9) << "Normal"; + msg << std::left << std::setw(9) << "W_MIMO"; + msg << std::left << std::setw(9) << "W_pinfor"; + msg << std::left << std::setw(9) << "Other"; + msg << std::endl; for (iter = all_database_dl_mode.begin(); iter != all_database_dl_mode.end(); iter++) { @@ -1198,25 +1312,26 @@ void MCSTracking::print_all_database_dl() { if ((iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0 && iter->second.nof_active > 0)) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "Unknown"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_retx; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "Unknown"; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; + msg << std::left << std::setw(9) << iter->second.nof_retx; int sc_percent = 0; if (iter->second.nof_newtx > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_harq; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_nom; - std::cout << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; - std::cout << std::left << std::setw(9) << iter->second.nof_pinfo; - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_harq; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_nom; + msg << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; + msg << std::left << std::setw(9) << iter->second.nof_pinfo; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_unknown++; num++; write_csv_file(iter->first, iter->second, iter->second.mcs_table); @@ -1226,9 +1341,9 @@ void MCSTracking::print_all_database_dl() for (int i = 0; i < 109; i++) { - std::cout << "-"; + msg << "-"; } - std::cout << std::endl; + msg << std::endl; for (iter = all_database_dl_mode.begin(); iter != all_database_dl_mode.end(); iter++) { @@ -1236,35 +1351,51 @@ void MCSTracking::print_all_database_dl() { if ((iter->second.nof_active > 0) && !(iter->second.nof_unsupport_mimo == 0 && iter->second.nof_pinfo == 0 && iter->second.nof_other_mimo == 0)) { - std::cout << std::left << std::setw(5) << num; - std::cout << std::left << std::setw(9) << iter->first; - std::cout << std::left << std::setw(12) << "Unknown"; - std::cout << std::left << std::setw(9) << iter->second.nof_active; - std::cout << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_retx; + msg << " "; + msg << std::left << std::setw(5) << num; + msg << std::left << std::setw(9) << iter->first; + msg << std::left << std::setw(12) << "Unknown"; + msg << std::left << std::setw(9) << iter->second.nof_active; + msg << RED << std::left << std::setw(9) << iter->second.nof_newtx << RESET; + msg << std::left << std::setw(9) << iter->second.nof_retx; int sc_percent = 0; if (iter->second.nof_newtx > 0) { sc_percent = std::roundf(((float)iter->second.nof_success_mgs / (float)iter->second.nof_active) * 100); } std::string sc_pc_str = std::to_string(iter->second.nof_success_mgs) + '(' + std::to_string(sc_percent) + "%)"; - std::cout << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_harq; - std::cout << std::left << std::setw(9) << iter->second.nof_success_retx_nom; - std::cout << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; - std::cout << std::left << std::setw(9) << iter->second.nof_pinfo; - std::cout << std::left << std::setw(9) << iter->second.nof_other_mimo; - std::cout << std::endl; + msg << BOLDGREEN << std::left << std::setw(13) << sc_pc_str << RESET; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_harq; + msg << std::left << std::setw(9) << iter->second.nof_success_retx_nom; + msg << std::left << std::setw(9) << iter->second.nof_unsupport_mimo; + msg << std::left << std::setw(9) << iter->second.nof_pinfo; + msg << std::left << std::setw(9) << iter->second.nof_other_mimo; + msg << std::endl; nof_unknown++; num++; } } } - printf("[256Tracking] Total: %d RNTIs are 64QAM table, %d RNTIs are 256QAM table, %d RNTIs are Unknown \n\n", - nof_64qam, nof_256qam, nof_unknown); + + msg << "[256Tracking] Total: "; + msg << std::right << std::setw(6) << nof_64qam; + msg << " RNTIs are 64QAM table, "; + msg << std::right << std::setw(6) << nof_256qam; + msg << " RNTIs are 256QAM table, "; + msg << std::right << std::setw(6) << nof_unknown; + msg << " RNTIs are Unknown "; + msg << std::endl; + msg << std::endl; + + if(DEBUG_TABLE_PRINT==1 && api_mode == -1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + filewriter_obj->write_stats(msg.str()); + } trackinglock.unlock(); -} +} // print_all_database_dl void MCSTracking::update_statistic_dl(uint16_t RNTI, bool tb_en[SRSRAN_MAX_CODEWORDS], @@ -1476,16 +1607,45 @@ void MCSTracking::update_ue_config_rnti(uint16_t rnti, ltesniffer_ue_spec_config ul_iter->second.ue_spec_config = ue_spec_config; } } + else if (sniffer_mode == DL_UL_MODE) + { + // Downlink + std::map::iterator dl_iter; + dl_iter = tracking_database_dl_mode.find(rnti); + if (dl_iter != tracking_database_dl_mode.end()) + { + dl_iter->second.ue_spec_config = ue_spec_config; + } + else + { + add_RNTI_dl(rnti, DL_SNIFFER_UNKNOWN_TABLE); + dl_iter = tracking_database_dl_mode.find(rnti); + dl_iter->second.ue_spec_config = ue_spec_config; + } + // Uplink + std::map::iterator ul_iter; + ul_iter = tracking_database_ul_mode.find(rnti); + if (ul_iter != tracking_database_ul_mode.end()) + { + ul_iter->second.ue_spec_config = ue_spec_config; + } + else + { + add_RNTI_ul(rnti, UL_SNIFFER_UNKNOWN_MOD); + ul_iter = tracking_database_ul_mode.find(rnti); + ul_iter->second.ue_spec_config = ue_spec_config; + } + } trackinglock.unlock(); } -ltesniffer_ue_spec_config_t MCSTracking::get_ue_config_rnti(uint16_t rnti) +ltesniffer_ue_spec_config_t MCSTracking::get_ue_config_rnti(uint16_t rnti, int DL_or_UL) { std::unique_lock trackinglock(tracking_mutex); ltesniffer_ue_spec_config_t ue_spec_config = {}; ue_spec_config = default_ue_spec_config; ue_spec_config.has_ue_config = false; - if (sniffer_mode == DL_MODE) + if (DL_or_UL == 0) { std::map::iterator dl_iter; dl_iter = tracking_database_dl_mode.find(rnti); @@ -1498,7 +1658,7 @@ ltesniffer_ue_spec_config_t MCSTracking::get_ue_config_rnti(uint16_t rnti) // nothing } } - else if (sniffer_mode == UL_MODE) + else if (DL_or_UL == 1) { std::map::iterator ul_iter; ul_iter = tracking_database_ul_mode.find(rnti); diff --git a/src/src/Phy.cc b/src/src/Phy.cc index 5c8e675..76acee7 100644 --- a/src/src/Phy.cc +++ b/src/src/Phy.cc @@ -10,6 +10,7 @@ Phy::Phy(uint32_t nof_rx_antennas, double metaFormatSplitRatio, uint32_t histogramThreshold, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, HARQ *harq, int mcs_tracking_mode, @@ -32,6 +33,7 @@ Phy::Phy(uint32_t nof_rx_antennas, common, metaFormats, pcapwriter, + filewriter_objs, mcs_tracking, harq, mcs_tracking_mode, diff --git a/src/src/SubframeWorker.cc b/src/src/SubframeWorker.cc index c533548..1449f5c 100644 --- a/src/src/SubframeWorker.cc +++ b/src/src/SubframeWorker.cc @@ -13,6 +13,7 @@ SubframeWorker::SubframeWorker(uint32_t idx, PhyCommon &common, DCIMetaFormats &metaFormats, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcs_tracking, HARQ *harq, int mcs_tracking_mode, @@ -28,6 +29,7 @@ SubframeWorker::SubframeWorker(uint32_t idx, updateMetaFormats(false), stats(), pcapwriter(pcapwriter), + filewriter_objs(filewriter_objs), mcs_tracking(mcs_tracking), harq(harq), harq_mode(harq_mode), @@ -51,7 +53,7 @@ SubframeWorker::SubframeWorker(uint32_t idx, /* Config for Downlink Sniffing function*/ srsran_ue_dl_init(falcon_ue_dl.q, sfb.sf_buffer, max_prb, common.nof_rx_antennas); /* PDSCH decoder (Downlink)*/ - pdschdecoder = new PDSCH_Decoder(idx, pcapwriter, mcs_tracking, common.getRNTIManager(), harq, mcs_tracking_mode, harq_mode, common.nof_rx_antennas); + pdschdecoder = new PDSCH_Decoder(idx, pcapwriter, filewriter_objs, mcs_tracking, common.getRNTIManager(), harq, mcs_tracking_mode, harq_mode, common.nof_rx_antennas); break; case UL_MODE: /* Config for Downlink Sniffing function*/ @@ -59,6 +61,7 @@ SubframeWorker::SubframeWorker(uint32_t idx, /* PDSCH decoder (Downlink)*/ pdschdecoder = new PDSCH_Decoder(idx, pcapwriter, + filewriter_objs, mcs_tracking, common.getRNTIManager(), harq, @@ -73,6 +76,39 @@ SubframeWorker::SubframeWorker(uint32_t idx, sfb.sf_buffer_offset, ul_cfg, pcapwriter, + filewriter_objs, + mcs_tracking, + mcs_tracking->get_debug_mode()); + /*Uplink enb init*/ + if (srsran_enb_ul_init(&enb_ul, sfb.sf_buffer[1], 110)) + { // 110 = max PRB + ERROR("Error initiating ENB UL"); + return; + } + break; + case DL_UL_MODE: + // Downlink/Uplink + /* Config for Downlink Sniffing function*/ + srsran_ue_dl_init(falcon_ue_dl.q, sfb.sf_buffer, max_prb, 1); // only 1 antenna for DL in the UL Sniffer Mode + /* PDSCH decoder (Downlink)*/ + pdschdecoder = new PDSCH_Decoder(idx, + pcapwriter, + filewriter_objs, + mcs_tracking, + common.getRNTIManager(), + harq, + mcs_tracking_mode, + harq_mode, + common.nof_rx_antennas); + /* PUSCH decoder (Uplink)*/ + puschdecoder = new PUSCH_Decoder(enb_ul, + ul_sf, + ulsche, + sfb.sf_buffer, + sfb.sf_buffer_offset, + ul_cfg, + pcapwriter, + filewriter_objs, mcs_tracking, mcs_tracking->get_debug_mode()); /*Uplink enb init*/ @@ -196,6 +232,22 @@ void SubframeWorker::work() // printf("[SIGNAL] Bad signal quality... \n"); } break; + case DL_UL_MODE: + dciSearch.prepareDCISearch(); // set single antenna for DL in the UL Sniffer mode + snr_ret = dciSearch.search(); + if (snr_ret == SRSRAN_SUCCESS) + { // only decode when SNR > 5 dB + stats += dciSearch.getStats(); // worker-specific statistics + common.addStats(dciSearch.getStats()); // common statistics + run_dl_mode(subframeInfo); + subframeInfo.getSubframePower().computePower(enb_ul.sf_symbols); + run_ul_mode(subframeInfo, tti); + } + else + { + // printf("[SIGNAL] Bad signal quality... \n"); + } + break; default: break; } diff --git a/src/src/UL_Sniffer_PUSCH.cc b/src/src/UL_Sniffer_PUSCH.cc index f18909b..10e6fa5 100644 --- a/src/src/UL_Sniffer_PUSCH.cc +++ b/src/src/UL_Sniffer_PUSCH.cc @@ -16,6 +16,7 @@ PUSCH_Decoder::PUSCH_Decoder(srsran_enb_ul_t &enb_ul, cf_t **buffer_offset, srsran_ul_cfg_t &ul_cfg, LTESniffer_pcap_writer *pcapwriter, + std::vector *filewriter_objs, MCSTracking *mcstracking, bool en_debug) : enb_ul(enb_ul), ul_sf(ul_sf), @@ -25,6 +26,7 @@ PUSCH_Decoder::PUSCH_Decoder(srsran_enb_ul_t &enb_ul, buffer_offset(buffer_offset), ul_cfg(ul_cfg), pcapwriter(pcapwriter), + filewriter_objs(filewriter_objs), sf_power(), mcstracking(mcstracking), en_debug(en_debug) @@ -273,7 +275,9 @@ void PUSCH_Decoder::decode_run(std::string info, DCI_UL &decoding_mem, std::stri tmp_sum += sf_power->getRBPowerUL().at(ul_cfg.pusch.grant.n_prb[0] + rb_idx); } falcon_signal_power = tmp_sum / ul_cfg.pusch.grant.L_prb; - print_debug(decoding_mem, info, modulation_mode, signal_power, enb_ul.chest_res.noise_estimate_dbm, falcon_signal_power); + srsran_dci_format_t cur_format = decoding_mem.format; + std::string dci_fm = dci_format_ul(cur_format); + print_debug(decoding_mem, dci_fm, info, modulation_mode, signal_power, enb_ul.chest_res.noise_estimate_dbm, falcon_signal_power); } if (pusch_res.crc == true && ul_cfg.pusch.grant.tb.tbs != 0) @@ -415,14 +419,27 @@ void PUSCH_Decoder::decode() { /*Investigate current decoding member to know it has a valid UL grant or not*/ valid_ul_grant = investigate_valid_ul_grant(decoding_mem); + valid_ul_grant_256 = investigate_valid_ul_grant_256(decoding_mem); + int some_valid_grant = (valid_ul_grant == SRSRAN_SUCCESS) || (valid_ul_grant_256 == SRSRAN_SUCCESS); /*Only decode member with valid UL grant*/ - if ((decoding_mem.rnti == target_rnti) || (valid_ul_grant == SRSRAN_SUCCESS)) + if (((decoding_mem.rnti == target_rnti) || (some_valid_grant == 1)) && decoding_mem.rnti != 0) { /*Setup uplink config for decoding*/ ul_cfg.pusch.rnti = decoding_mem.rnti; ul_cfg.pusch.enable_64qam = false; // check here for 64/16QAM ul_cfg.pusch.meas_ta_en = true; // enable ta measurement - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant.get(); + // start + bool set_grant = false; + if(valid_ul_grant == SRSRAN_SUCCESS){ + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant; + set_grant = true; + } + if((set_grant == false) && (valid_ul_grant_256 == SRSRAN_SUCCESS)){ + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256; + set_grant = true; + } + if(set_grant == false){continue;} + // end int mcs_idx = ul_cfg.pusch.grant.tb.mcs_idx; pusch_res.crc = false; /*Get Number of ack which was calculated in Subframe worker last 4 ms*/ @@ -430,7 +447,7 @@ void PUSCH_Decoder::decode() // ul_cfg.pusch.uci_cfg.cqi.rank_is_not_one = (decoding_mem.nof_ack == 2)?true:false; /*get UE-specific configuration from database*/ - ltesniffer_ue_spec_config_t ue_config = mcstracking->get_ue_config_rnti(decoding_mem.rnti); + ltesniffer_ue_spec_config_t ue_config = mcstracking->get_ue_config_rnti(decoding_mem.rnti, 1); ul_cfg.pusch.uci_cfg.cqi.type = ue_config.cqi_config.type; ul_cfg.pusch.uci_offset = ue_config.uci_config; /*If eNB requests for Aperiodic CSI report*/ @@ -473,7 +490,8 @@ void PUSCH_Decoder::decode() decoding_mem.mcs_mod = UL_SNIFFER_256QAM_MAX; ul_cfg.pusch.enable_64qam = true; modulation_mode = modulation_mode_string_256(mcs_idx); - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256.get(); + if(valid_ul_grant_256 == SRSRAN_ERROR){continue;} + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256; if (ul_cfg.pusch.grant.L_prb < 110 && ul_cfg.pusch.grant.L_prb > 0) { decode_run("[PUSCH-256]", decoding_mem, modulation_mode, 0); @@ -503,16 +521,18 @@ void PUSCH_Decoder::decode() ul_cfg.pusch.rnti = decoding_mem.rnti; ul_cfg.pusch.enable_64qam = true; // 64QAM ul_cfg.pusch.meas_ta_en = true; // enable ta measurement - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant.get(); - - decode_run("[PUSCH-64 ]", decoding_mem, modulation_mode, falcon_signal_power); - + if(valid_ul_grant == SRSRAN_SUCCESS){ + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant; + decode_run("[PUSCH-64 ]", decoding_mem, modulation_mode, falcon_signal_power); + } + if (pusch_res.crc == false) { // try 256QAM table if 2 cases above failed ul_cfg.pusch.rnti = decoding_mem.rnti; ul_cfg.pusch.enable_64qam = true; ul_cfg.pusch.meas_ta_en = true; // enable ta measurement - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256.get(); + if(valid_ul_grant_256 == SRSRAN_ERROR){continue;} + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256; modulation_mode = modulation_mode_string_256(mcs_idx); if (ul_cfg.pusch.grant.L_prb < 110 && ul_cfg.pusch.grant.L_prb > 0) { @@ -542,7 +562,8 @@ void PUSCH_Decoder::decode() break; case UL_SNIFFER_256QAM_MAX: ul_cfg.pusch.enable_64qam = true; - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256.get(); + if(valid_ul_grant_256 == SRSRAN_ERROR){continue;} + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256; modulation_mode = modulation_mode_string_256(mcs_idx); if (ul_cfg.pusch.grant.L_prb < 110 && ul_cfg.pusch.grant.L_prb > 0) { @@ -555,7 +576,8 @@ void PUSCH_Decoder::decode() decode_run("[PUSCH-16 ]", decoding_mem, modulation_mode, 0); if (pusch_res.crc == false) { // try 256QAM table if case above failed - ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256.get(); + if(valid_ul_grant_256 == SRSRAN_ERROR){continue;} + ul_cfg.pusch.grant = *decoding_mem.ran_ul_grant_256; modulation_mode = modulation_mode_string_256(mcs_idx); if (ul_cfg.pusch.grant.L_prb < 110 && ul_cfg.pusch.grant.L_prb > 0) { @@ -711,32 +733,52 @@ void PUSCH_Decoder::work_prach() } } } - -void PUSCH_Decoder::print_debug(DCI_UL &decoding_mem, std::string offset_name, std::string modulation_mode, float signal_pw, double noise, double falcon_sgl_pwr) +// FIO FILE_IDX_UL_DCI +void PUSCH_Decoder::print_debug( DCI_UL &decoding_mem, + std::string format, + std::string offset_name, + std::string modulation_mode, + float signal_pw, + double noise, + double falcon_sgl_pwr) { - std::cout << std::left << std::setw(12) << offset_name << " SF: "; - std::cout << std::left << std::setw(4) << (int)ul_sf.tti / 10 << "." << (int)ul_sf.tti % 10; - std::cout << " -- RNTI: "; - std::cout << std::left << std::setw(6) << decoding_mem.rnti; + std::stringstream msg; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg << "[" << cur_time_second << "]: "; + + msg << std::left << std::setw(12) << offset_name << " SF: "; + msg << std::left << std::setw(4) << (int)ul_sf.tti / 10 << "." << (int)ul_sf.tti % 10; + msg << " -- RNTI: "; + msg << std::left << std::setw(6) << decoding_mem.rnti; + msg << WHITE << " -- DCI: " << std::left << std::setw(4) << format << RESET; - std::cout << GREEN << " -- DL-UL(us): "; + msg << GREEN << " -- DL-UL(us): "; if (enb_ul.chest_res.ta_us > 0) { - std::cout << "+"; + msg << "+"; } else if (enb_ul.chest_res.ta_us < 0) { - std::cout << "-"; + msg << "-"; } else { - std::cout << " "; + msg << " "; } - std::cout << std::left << std::setw(5) << abs(enb_ul.chest_res.ta_us) << RESET; - std::cout << " -- SNR(db): "; - std::cout << std::left << std::setw(6) << std::setprecision(3) << enb_ul.chest_res.snr_db; + msg << std::left << std::setw(5) << abs(enb_ul.chest_res.ta_us) << RESET; + msg << " -- SNR(db): "; + msg << std::left << std::setw(6) << std::setprecision(3) << enb_ul.chest_res.snr_db; - // std::cout << " -- F_Pwr: "; + // msg << " -- F_Pwr: "; // std::string pwr_sign; // int width = 0; // if (falcon_sgl_pwr < 0) { @@ -747,40 +789,86 @@ void PUSCH_Decoder::print_debug(DCI_UL &decoding_mem, std::string offset_name, s // pwr_sign = " "; // width = 6; // } - // std::cout << std::left << pwr_sign << std::setw(width) << std::setprecision(3) << falcon_sgl_pwr; + // msg << std::left << pwr_sign << std::setw(width) << std::setprecision(3) << falcon_sgl_pwr; - std::cout << " -- CQI RQ: "; - std::cout << decoding_mem.ran_ul_dci->cqi_request << "|" << decoding_mem.ran_ul_dci->multiple_csi_request_present; + msg << " -- CQI RQ: "; + msg << decoding_mem.ran_ul_dci->cqi_request << "|" << decoding_mem.ran_ul_dci->multiple_csi_request_present; - std::cout << " -- Noise Pwr: "; - std::cout << std::left << std::setw(6) << std::setprecision(3) << noise; + msg << " -- Noise Pwr: "; + msg << std::left << std::setw(6) << std::setprecision(3) << noise; - std::cout << YELLOW << " -- MCS: "; - std::cout << std::left << std::setw(3) << ul_cfg.pusch.grant.tb.mcs_idx << RESET; + msg << YELLOW << " -- MCS: "; + msg << std::left << std::setw(3) << ul_cfg.pusch.grant.tb.mcs_idx << RESET; - std::cout << YELLOW << " -- "; - std::cout << std::left << std::setw(6) << modulation_mode << RESET; + msg << YELLOW << " -- "; + msg << std::left << std::setw(6) << modulation_mode << RESET; - std::cout << " -- "; + msg << " -- "; if (pusch_res.crc == false) { - std::cout << RED << std::setw(7) << "FAILED" << RESET; - std::cout << " -- Len: " << ul_cfg.pusch.grant.tb.tbs / 8; + msg << RED << std::setw(7) << "FAILED" << RESET; + msg << " -- Len: " << ul_cfg.pusch.grant.tb.tbs / 8; } else { - std::cout << BOLDGREEN << std::setw(7) << "SUCCESS" << RESET; - std::cout << " -- Len: " << ul_cfg.pusch.grant.tb.tbs / 8; + msg << BOLDGREEN << std::setw(7) << "SUCCESS" << RESET; + msg << " -- Len: " << ul_cfg.pusch.grant.tb.tbs / 8; } if (decoding_mem.is_rar_gant) { - std::cout << " -- RAR"; + msg << " -- RAR"; + //std::cout << "RAR RAR RAR RAR RAR RAR" << std::endl; } if (decoding_mem.is_retx == 1) { - std::cout << " -- ReTX-UL"; + msg << " -- ReTX-UL"; } - std::cout << std::endl; + msg << std::endl; + if(DEBUG_DCI_PRINT==1){ + std::cout << msg.str(); + } + if(FILE_WRITE==1){ + (*filewriter_objs)[FILE_IDX_UL_DCI]->write_stats(msg.str()); + } +} + +std::string PUSCH_Decoder::dci_format_ul(int format) +{ + std::string ret = "UNKNOWN"; + switch (format) + { + case 0: + ret = "0"; + break; + case 1: + ret = "1"; + break; + case 2: + ret = "1A"; + break; + case 3: + ret = "1B"; + break; + case 4: + ret = "1C"; + break; + case 5: + ret = "1D"; + break; + case 6: + ret = "2"; + break; + case 7: + ret = "2A"; + break; + case 8: + ret = "2B"; + break; + default: + ret = "UNKNOWN"; + break; + } + return ret; } void PUSCH_Decoder::print_success(DCI_UL &decoding_mem, std::string offset_name, int table) @@ -881,37 +969,90 @@ std::string convert_msg_name(int msg) } void PUSCH_Decoder::print_api(uint32_t tti, uint16_t rnti, int id, std::string value, int msg) { - std::cout << std::left << std::setw(4) << tti / 10 << "-" << std::left << std::setw(5) << tti % 10; + std::stringstream msg_api; + + auto now = std::chrono::system_clock::now(); + std::time_t cur_time = std::chrono::system_clock::to_time_t(now); + std::string str_cur_time(std::ctime(&cur_time)); + std::string cur_time_second; + if(str_cur_time.length()>=(11+8)){ + cur_time_second = str_cur_time.substr(11,8); + }else{ + cur_time_second = ""; + } + msg_api << "[" << cur_time_second << "]: "; + + msg_api << std::left << std::setw(4) << tti / 10 << "-" << std::left << std::setw(5) << tti % 10; std::string id_name = convert_id_name(id); - std::cout << std::left << std::setw(26) << id_name; - std::cout << std::left << std::setw(17) << value; - std::cout << std::left << std::setw(11) << rnti; + msg_api << std::left << std::setw(26) << id_name; + msg_api << std::left << std::setw(17) << value; + msg_api << std::left << std::setw(11) << rnti; std::string msg_name = convert_msg_name(msg); - std::cout << std::left << std::setw(25) << msg_name; - std::cout << std::endl; -} + msg_api << std::left << std::setw(25) << msg_name; + msg_api << std::endl; + if(DEBUG_SEC_PRINT==1){ + std::cout << msg_api.str(); + } + if(FILE_WRITE==1){ + (*filewriter_objs)[FILE_IDX_API]->write_stats(msg_api.str()); + } +} // UL int PUSCH_Decoder::investigate_valid_ul_grant(DCI_UL &decoding_mem) { int ret = SRSRAN_SUCCESS; + /*if RNTI == 0*/ + if (decoding_mem.rnti == 0) + { + return SRSRAN_ERROR; + } + if(decoding_mem.ran_ul_grant==nullptr) + { + return SRSRAN_ERROR; + } if (decoding_mem.is_rar_gant) { return SRSRAN_SUCCESS; } + /*if Transport Block size = 0 (wrong DCI detection or retransmission or pdsch for ack and uci)*/ + if (decoding_mem.ran_ul_grant->tb.tbs == 0) + { + return SRSRAN_ERROR; + } + /*if number of PRB is invalid*/ + if (!check_valid_prb_ul(decoding_mem.ran_ul_grant->L_prb)) + { + return SRSRAN_ERROR; + } + + return ret; +} + +int PUSCH_Decoder::investigate_valid_ul_grant_256(DCI_UL &decoding_mem) +{ + int ret = SRSRAN_SUCCESS; /*if RNTI == 0*/ if (decoding_mem.rnti == 0) { - ret = SRSRAN_ERROR; + return SRSRAN_ERROR; + } + if(decoding_mem.ran_ul_grant_256==nullptr) + { + return SRSRAN_ERROR; + } + if (decoding_mem.is_rar_gant) + { + return SRSRAN_SUCCESS; } /*if Transport Block size = 0 (wrong DCI detection or retransmission or pdsch for ack and uci)*/ - if (decoding_mem.ran_ul_grant->tb.tbs == 0 || decoding_mem.ran_ul_grant_256->tb.tbs == 0) + if (decoding_mem.ran_ul_grant_256->tb.tbs == 0) { - ret = SRSRAN_ERROR; + return SRSRAN_ERROR; } /*if number of PRB is invalid*/ - if (!check_valid_prb_ul(decoding_mem.ran_ul_grant->L_prb)) + if (!check_valid_prb_ul(decoding_mem.ran_ul_grant_256->L_prb)) { - ret = SRSRAN_ERROR; + return SRSRAN_ERROR; } return ret; diff --git a/srsRAN_4G_mirror/.clang-format b/srsRAN_4G_mirror/.clang-format new file mode 100644 index 0000000..3be90d0 --- /dev/null +++ b/srsRAN_4G_mirror/.clang-format @@ -0,0 +1,112 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true #Changed +AlignConsecutiveDeclarations: true #Changed +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false # Changed +#AllowAllArgumentsOnNextLine: false # Changed +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline #Changed +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true #Changed +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: true #Changed + AfterControlStatement: false + AfterEnum: false + AfterFunction: true #Changed + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false #Changed + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom #Changed +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon #Changed +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 #Changed +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true #Changed +ConstructorInitializerIndentWidth: 2 #Changed +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true #Changed +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left #Changed +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp03 #Changed +TabWidth: 8 +UseTab: Never +... + diff --git a/srsRAN_4G_mirror/.clang-tidy b/srsRAN_4G_mirror/.clang-tidy new file mode 100644 index 0000000..874dd51 --- /dev/null +++ b/srsRAN_4G_mirror/.clang-tidy @@ -0,0 +1,37 @@ +--- +# All Clang-Tidy Checks allowed, except: +# - forbidden vararg +# - forbidden magic numbers +# - forbidden namespace "using" +# - forbidden array->pointer decay +# - init of static memory may cause an exception (cert-err58) +# - forbidden implicit conversion from pointer/int to bool +# - recommended auto +# - remove llvm-specific checks (header guard style, usage of llvm namespace, restriction of libc includes, etc.) +# Naming conventions set to snake_case +Checks: '*,-fuchsia-*, + -cppcoreguidelines-pro-type-vararg,-hicpp-vararg, + -cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay, + -cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-type-cstyle-cast, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-static-cast-downcast, + -modernize-use-using,-modernize-use-trailing-return-type, + -modernize-use-auto,-hicpp-use-auto, + -llvmlibc-callee-namespace,-llvmlibc-implementation-in-namespace,-llvmlibc-restrict-system-libc-headers, + -llvm-header-guard, + -google-runtime-references,-google-readability-casting,-google-build-using-namespace, + google-default-arguments,-cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cert-err58-cpp, + -readability-function-cognitive-complexity,-readability-isolate-declaration, + -misc-non-private-member-variables-in-classes,-altera-struct-pack-align,-readability-uppercase-literal-suffix, + -cppcoreguidelines-non-private-member-variables-in-classes, + readability-identifier-naming' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +CheckOptions: + - { key: readability-identifier-naming.NamespaceCase, value: lower_case } + - { key: readibility-identifier-naming.ClassCase, value: lower_case } + - { key: readibility-identifier-naming.StructCase, value: lower_case } + - { key: readibility-identifier-naming.VariableCase, value: lower_case } + diff --git a/srsRAN_4G_mirror/.gdbinit b/srsRAN_4G_mirror/.gdbinit new file mode 100644 index 0000000..bb7d55d --- /dev/null +++ b/srsRAN_4G_mirror/.gdbinit @@ -0,0 +1,42 @@ +# +# Copyright 2013-2020 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +############################################ +# Pretty-Printers +############################################ + +python + +###### srsran::bounded_vector ######## + +class BoundedVectorPrinter(object): + def __init__(self, val): + self.val = val + self.value_type = self.val.type.template_argument(0) + + def children(self): + start = self.val['buffer']['_M_elems'].cast(self.value_type.pointer()) + length = int(self.val['size_']) + for idx in range(length): + yield f'[{idx}]', start[idx] + + def to_string(self): + length = int(self.val['size_']) + capacity = int(self.val.type.template_argument(1)) + return f'bounded_vector of length {length}, capacity {capacity}' + + def display_hint(self): + return 'array' + +def make_bounded_vector(val): + if 'bounded_vector<' in str(val.type): + return BoundedVectorPrinter(val) + +gdb.pretty_printers.append(make_bounded_vector) + +end diff --git a/srsRAN_4G_mirror/.github/ISSUE_TEMPLATE.md b/srsRAN_4G_mirror/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..b2cdc03 --- /dev/null +++ b/srsRAN_4G_mirror/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,24 @@ + + +## Issue Description ## +[Describe the issue in detail] + +## Setup Details ## +[Specify details of the test setup. This would help us reproduce the problem reliably] +e.g. Network configuration, Operation System, Hardware, RF front-end, library and driver versions + +## Expected Behavior ## +[What you expect to happen] + +## Actual Behaviour ## +[What happens instead e.g. error message] + +## Steps to reproduce the problem ## +[Tell us how to reproduce this issue e.g. RF setup, application config files] + +## Additional Information ## +[Any additional information, configuration or data that might be necessary to reproduce the issue] + diff --git a/srsRAN_4G_mirror/.github/workflows/ccpp.yml b/srsRAN_4G_mirror/.github/workflows/ccpp.yml new file mode 100644 index 0000000..8272df7 --- /dev/null +++ b/srsRAN_4G_mirror/.github/workflows/ccpp.yml @@ -0,0 +1,48 @@ +name: C/C++ CI +on: push +jobs: + x86_ubuntu18_build: + name: Build and test on x86 Ubuntu 18.04 + strategy: + matrix: + compiler: [gcc, clang] + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v1 + - name: Build srsRAN on x86 Ubuntu 18.04 + run: | + sudo apt update + sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind + mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest + x86_ubuntu16_build: + name: Build and test on x86 Ubuntu 16.04 + strategy: + matrix: + compiler: [gcc, clang] + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v1 + - name: Build srsRAN on x86 Ubuntu 16.04 + run: | + sudo apt update + sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind + mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest + + aarch64_ubuntu18_build: + runs-on: ubuntu-18.04 + name: Build on aarch64 + strategy: + matrix: + compiler: [gcc, clang] + steps: + - uses: actions/checkout@v1 + - name: Build srsRAN on aarch64 + uses: uraimo/run-on-arch-action@master + with: + architecture: aarch64 + distribution: ubuntu18.04 + run: | + export CTEST_PARALLEL_LEVEL=$(nproc --all) + apt update + apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev ninja-build + ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja \ No newline at end of file diff --git a/srsRAN_4G_mirror/.lgtm.yml b/srsRAN_4G_mirror/.lgtm.yml new file mode 100644 index 0000000..3edf9c2 --- /dev/null +++ b/srsRAN_4G_mirror/.lgtm.yml @@ -0,0 +1,23 @@ +extraction: + cpp: + prepare: + packages: + - build-essential + - cmake + - libfftw3-dev + - libmbedtls-dev + - libpcsclite-dev + - libboost-program-options-dev + - libconfig++-dev + - libsctp-dev + - libuhd-dev + - libzmq3-dev + configure: + command: + - mkdir build + - cd build + - cmake .. + index: + build_command: + - cd build + - make diff --git a/srsRAN_4G_mirror/.travis.yml b/srsRAN_4G_mirror/.travis.yml new file mode 100644 index 0000000..e53a2a7 --- /dev/null +++ b/srsRAN_4G_mirror/.travis.yml @@ -0,0 +1,31 @@ +dist: bionic +sudo: required + +before_script: + - sudo apt-get -qq update + - sudo apt-get install -qq build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev libczmq-dev libpcsclite-dev rapidjson-dev colordiff ninja-build clang-format-8 + +language: cpp + +compiler: + - gcc + - clang + +script: + - sudo ln -s /usr/bin/clang-format-diff-8 /usr/bin/clang-format-diff + - git remote set-branches --add origin master + - git fetch + - | + if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then + # Run only for PRs because target branch is needed to do the clang-format check + echo "Checking clang-format between TRAVIS_BRANCH=$TRAVIS_BRANCH and TRAVIS_PULL_REQUEST_BRANCH=$TRAVIS_PULL_REQUEST_BRANCH" + ./run-clang-format-diff.sh "$TRAVIS_BRANCH" "$TRAVIS_PULL_REQUEST_BRANCH" + else + echo "Skipping clang-format check" + fi + - mkdir build + - cd build + - cmake -DENABLE_TTCN3=True -DRF_FOUND=True -G Ninja .. + - ninja + - ninja test + - sudo ninja install \ No newline at end of file diff --git a/srsRAN_4G_mirror/CHANGELOG b/srsRAN_4G_mirror/CHANGELOG new file mode 100644 index 0000000..bdc185d --- /dev/null +++ b/srsRAN_4G_mirror/CHANGELOG @@ -0,0 +1,189 @@ +Change Log for Releases +======================= + +## 21.10 + * Add initial 5G NSA support to srsENB (tested with OnePlus 5G Nord) + * Improved interoperability of srsUE in NSA mode + * Added enhanced instrumentation to file using JSON format + * Fixed stability issues with Ettus N310 + * Added BLER-adaptive MCS scheduling to srsENB + * Other bug-fixes and improved stability and performance in all parts + +## 21.04 + * Rename project from srsLTE to srsRAN + * Add initial 5G NSA support to srsUE (including x86-optimized FEC and PHY layer) + * Add PDCP discard support + * Add UL power control, measurement gaps and a new proportional fair scheduler to srsENB + * Extend GTP-U tunneling to support tunnel forwarding over S1 + * Optimize many data structures, remove dynamic memory allocations in data plane + * Improved S1AP error handling and enhanced event reporting + * Update ASN.1 packing/unpacking, RRC to Rel 15.11, S1AP to Rel 16.1 + * Update PCAP writer to use UDP framing + * Other bug-fixes and improved stability and performance in all parts + +## 20.10.1 + * Fix bug in srsENB that effectively disabled UL HARQ + +## 20.10 + * Add Mobility (Intra eNB and S1) and RRC Reestablishment to srsENB + * Add new logging framework + * Make UE PHY layer non-blocking + * Replace some PHY pre-calculations with fast on-the-fly routines + * Fix QAM256 support in srsENB + * Add initial NR PHY layer and stack components + * Other bug-fixes and improved stability and performance in all parts + +## 20.04.2 + * Fix attach issue for some newer phones due to wrong CQI config + in RRC Connection Reconfiguration message by turning off QAM256 support + +## 20.04.1 + * Fix for UE MIMO segfault issue + * Fix for eNodeB SR configuration + * Clang compilation warning fixes + * Fix GPS tracking synchronization + +## 20.04 + * Carrier Aggregation and Time Alignment in srsENB + * Complete Sidelink PHY layer (all transmission modes) + * Complete NB-IoT PHY downlink signals + * New S1AP packing/unpacking library + * EVM and EPRE measurements + * Remove system timers in srsUE and srsENB + * Refactor eNB to prepare for mobility support + * Other bug-fixes and improved stability and performance in all parts + +## 19.12 + * Add 5G NR RRC and NGAP ASN1 packing/unpacking + * Add sync routines and broadcast channel for Sidelink + * Add cell search and MIB decoder for NB-IoT + * Add PDCP discard + * Improve RRC Reestablishment handling + * Improve RRC cell measurements and procedure handling + * Add multi-carrier and MIMO support to ZMQ radio + * Refactor eNB scheduler to support multiple carriers + * Apply clang-format style on entire code base + * Other bug-fixes and improved stability and performance in all parts + +## 19.09 + * Add initial support for NR in MAC/RLC/PDCP + * Add sync code for NB-IoT + * Add support for EIA3/EEA3 (i.e. ZUC) + * Add support for CSFB in srsENB + * Add adaptation layer to run TTCN-3 conformance tests for srsUE + * Add High Speed Train model to channel simulator + * Rework RRC and NAS layer and make them non-blocking + * Fixes in ZMQ, bladeRF and Soapy RF modules + * Other bug-fixes and improved stability and performance in all parts + +## 19.06 + * Add QAM256 support in srsUE + * Add QoS support in srsUE + * Add UL channel emulator + * Refactor UE and eNB architecture + * Many bug-fixes and improved stability and performance in all parts + +## 19.03 + * PHY library refactor + * TDD support for srsUE + * Carrier Aggregation support for srsUE + * Paging support for srsENB and srsEPC + * User-plane encryption for srsENB + * Channel simulator for EPA, EVA, and ETU 3GPP channels + * ZeroMQ-based fake RF driver for I/Q over IPC/network + * Many bug-fixes and improved stability and performance in all parts + +## 18.12 + * Add new RRC ASN1 message pack/unpack library + * Refactor EPC and add encryption support + * Add IPv6 support to srsUE + * Fixed compilation issue for ARM and AVX512 + * Add clang-format file + * Many bug-fixes and improved stability and performance in all parts + +## 18.09 + * Improved Turbo Decoder performance + * Configurable SGi interface name and M1U params + * Support for GPTU echo mechanism + * Added UE detach capability + * Refactor RLC/PDCP classes + * Various fixes for ARM-based devices + * Added support for bladeRF 2.0 micro + * Many bug-fixes and improved stability and performance in all parts + +## 18.06.1 + * Fixed RLC reestablish + * Fixed aperiodic QCI retx + * Fixed eNB instability + * Fixed Debian packaging + +## 18.06 + * Added eMBMS support in srsUE/srsENB/srsEPC + * Added support for hard SIM cards + * Many bug-fixes and improved stability and performance in all parts + +## 18.03.1 + * Fixed compilation for NEON + * Fixed logging and RLC AM issue + +## 18.03 + * Many bug-fixes and improved stability and performance in all parts + +## 17.12 + * Added support for MIMO 2x2 in srsENB (i.e. TM3/TM4) + * Added srsEPC, a light-weight core network implementation + * Added support for X2/S1 handover in srsUE + * Added support for user-plane encryption in srsUE + * Many bug-fixes and improved stability and performance in srsUE/srsENB + +## 17.09 + * Added MIMO 2x2 in the PHY layer and srsUE (i.e. TM3/TM4) + * eMBMS support in the PHY layer + * Many bug-fixes and improved stability and performance in srsUE/srsENB + +## 002.000.000 + * Added fully functional srsENB to srsLTE code + * Merged srsUE code into srsLTE and reestructured PHY code + * Added support for SoapySDR devices (eg LimeSDR) + * Fixed issues in RLC AM + * Added support for NEON and AVX in many kernels and Viterbi decoder + * Added support for CPU affinity + * Other minor bug-fixes and new features + +## 001.004.000 + * Fixed issue in rv for format1C causing incorrect SIB1 decoding in some networks + * Improved PDCCH decoding BER (fixed incorrect trellis initialization) + * Improved PUCCH RX performance + +## 001.003.000 + +* Bugfixes: + * x300 master clock rate + * PHICH: fixed bug causing more NACKs + * PBCH: fixed bug in encoding function + * channel estimation: fixed issue in time interpolation + * DCI: Fixed bug in Format1A packing + * DCI: Fixed bug in Format1C for RA-RNTI + * DCI: Fixed overflow in MIMO formats + +* Improvements: + * Changed and cleaned DCI blind search API + * Added eNodeB PHY processing functions + +## 001.002.000 + +* Bugfixes: + * Estimation of extrapolated of out-of-band carriers + * PDCCH REG interleaving for certain cell IDs + * MIB decoding + * Overflow in viterbi in PBCH + +* Improvements: + * Synchronization in long multipath channels + * Better calibration of synchronization and estimation + * Averaging in channel estimation + * Improved 2-port diversity decoding + + +## 001.001.000 +* Added support for BladeRF diff --git a/srsRAN_4G_mirror/CMakeLists.txt b/srsRAN_4G_mirror/CMakeLists.txt new file mode 100644 index 0000000..26bf960 --- /dev/null +++ b/srsRAN_4G_mirror/CMakeLists.txt @@ -0,0 +1,689 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + + +######################################################################## +# Prevent in-tree builds +######################################################################## +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "Prevented in-tree build. This is bad practice.") +endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + + +######################################################################## +# Project setup +######################################################################## +cmake_minimum_required(VERSION 2.6) +project( SRSRAN ) +message( STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM} ) +message( STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR} ) +message( STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER} ) + +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") +include(SRSRANVersion) #sets version information +include(SRSRANPackage) #setup cpack + +include(CTest) + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake" + IMMEDIATE @ONLY) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + message(STATUS "Build type not specified: defaulting to Release.") +endif(NOT CMAKE_BUILD_TYPE) +set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") + +# Generate CMake to include build information +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/modules/SRSRANbuildinfo.cmake.in + ${CMAKE_BINARY_DIR}/SRSRANbuildinfo.cmake +) + +######################################################################## +# Options +######################################################################## +option(ENABLE_SRSUE "Build srsUE application" ON) +option(ENABLE_SRSENB "Build srsENB application" ON) +option(ENABLE_SRSEPC "Build srsEPC application" ON) +option(DISABLE_SIMD "Disable SIMD instructions" OFF) +option(AUTO_DETECT_ISA "Autodetect supported ISA extensions" ON) + +option(ENABLE_GUI "Enable GUI (using srsGUI)" OFF) +option(ENABLE_UHD "Enable UHD" ON) +option(ENABLE_BLADERF "Enable BladeRF" ON) +option(ENABLE_SOAPYSDR "Enable SoapySDR" ON) +option(ENABLE_SKIQ "Enable Sidekiq SDK" ON) +option(ENABLE_ZEROMQ "Enable ZeroMQ" ON) +option(ENABLE_HARDSIM "Enable support for SIM cards" ON) + +option(ENABLE_TTCN3 "Enable TTCN3 test binaries" OFF) +option(ENABLE_ZMQ_TEST "Enable ZMQ based E2E tests" OFF) + +option(BUILD_STATIC "Attempt to statically link external deps" OFF) +option(RPATH "Enable RPATH" OFF) +option(ENABLE_ASAN "Enable gcc/clang address sanitizer" OFF) +option(ENABLE_GCOV "Enable gcc/clang address sanitizer" OFF) +option(ENABLE_MSAN "Enable clang memory sanitizer" OFF) +option(ENABLE_TSAN "Enable clang thread sanitizer" OFF) +option(ENABLE_TIDY "Enable clang tidy" OFF) + +option(USE_LTE_RATES "Use standard LTE sampling rates" OFF) +option(USE_MKL "Use MKL instead of fftw" OFF) + +option(ENABLE_TIMEPROF "Enable time profiling" ON) + +option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF) + +option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" OFF) +option(ASSERTS_ENABLED "Enable srsRAN asserts" ON) +option(STOP_ON_WARNING "Interrupt application on warning" OFF) + +option(ENABLE_ALL_TEST "Enable all unit/component test" OFF) + +# Users that want to try this feature need to make sure the lto plugin is +# loaded by bintools (ar, nm, ...). Older versions of bintools will not do +# it automatically so it is necessary to use the gcc wrappers of the compiler +# (gcc-ar, gcc-nm, ...). +option(BUILD_WITH_LTO "Enable LTO (experimental)" OFF) + +if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(GCC_ARCH armv8-a CACHE STRING "GCC compile for specific architecture.") + message(STATUS "Detected aarch64 processor") +else(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(GCC_ARCH native CACHE STRING "GCC compile for specific architecture.") +endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + +# On RAM constrained (embedded) systems it may be useful to limit parallel compilation with, e.g. -DPARALLEL_COMPILE_JOBS=1 +if (PARALLEL_COMPILE_JOBS) + set(CMAKE_JOB_POOL_COMPILE compile_job_pool${CMAKE_CURRENT_SOURCE_DIR}) + string (REGEX REPLACE "[^a-zA-Z0-9]+" "_" CMAKE_JOB_POOL_COMPILE ${CMAKE_JOB_POOL_COMPILE}) + set_property(GLOBAL APPEND PROPERTY JOB_POOLS ${CMAKE_JOB_POOL_COMPILE}=${PARALLEL_COMPILE_JOBS}) + message(STATUS "${CMAKE_CURRENT_SOURCE_DIR}: Limiting compiler jobs to ${PARALLEL_COMPILE_JOBS}") +endif () + +if (ENABLE_SRSLOG_TRACING) + add_definitions(-DENABLE_SRSLOG_EVENT_TRACE) +endif (ENABLE_SRSLOG_TRACING) + +if (ASSERTS_ENABLED) + add_definitions(-DASSERTS_ENABLED) +endif() + +if (STOP_ON_WARNING) + add_definitions(-DSTOP_ON_WARNING) +endif() + +# Test for Atomics +include(CheckAtomic) +if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB OR NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + set(ATOMIC_LIBS "atomic") +endif() + +######################################################################## +# Find dependencies +######################################################################## + +# Enable ccache if not already enabled +find_program(CCACHE_EXECUTABLE ccache) +mark_as_advanced(CCACHE_EXECUTABLE) +if(CCACHE_EXECUTABLE) + foreach(LANG C CXX) + if(NOT DEFINED CMAKE_${LANG}_COMPILER_LAUNCHER AND NOT CMAKE_${LANG}_COMPILER MATCHES ".*/ccache$") + message(STATUS "Enabling ccache for ${LANG}") + set(CMAKE_${LANG}_COMPILER_LAUNCHER ${CCACHE_EXECUTABLE} CACHE STRING "") + endif() + endforeach() +endif() + +# Threads +find_package(Threads REQUIRED) + +# FFT +if(USE_MKL) + find_package(MKL REQUIRED) + include_directories(${MKL_INCLUDE_DIRS}) + link_directories(${MKL_LIBRARY_DIRS}) + set(FFT_LIBRARIES "${MKL_STATIC_LIBRARIES}") # Static by default +else(USE_MKL) + find_package(FFTW3F REQUIRED) + if(FFTW3F_FOUND) + include_directories(${FFTW3F_INCLUDE_DIRS}) + link_directories(${FFTW3F_LIBRARY_DIRS}) + if(BUILD_STATIC) + set(FFT_LIBRARIES "${FFTW3F_STATIC_LIBRARIES}") + else(BUILD_STATIC) + set(FFT_LIBRARIES "${FFTW3F_LIBRARIES}") + endif(BUILD_STATIC) + message(STATUS "FFT_LIBRARIES: " ${FFT_LIBRARIES}) + endif(FFTW3F_FOUND) +endif(USE_MKL) + +# Crypto +find_package(Polarssl) +if (POLARSSL_FOUND) + set(SEC_INCLUDE_DIRS "${POLARSSL_INCLUDE_DIRS}") + if(BUILD_STATIC) + set(SEC_LIBRARIES "${POLARSSL_STATIC_LIBRARIES}") + else(BUILD_STATIC) + set(SEC_LIBRARIES "${POLARSSL_LIBRARIES}") + endif(BUILD_STATIC) + add_definitions(-DHAVE_POLARSSL) +else(POLARSSL_FOUND) + find_package(MbedTLS REQUIRED) + if (MBEDTLS_FOUND) + set(SEC_INCLUDE_DIRS "${MBEDTLS_INCLUDE_DIRS}") + if(BUILD_STATIC) + set(SEC_LIBRARIES "${MBEDTLS_STATIC_LIBRARIES}") + else(BUILD_STATIC) + set(SEC_LIBRARIES "${MBEDTLS_LIBRARIES}") + endif(BUILD_STATIC) + add_definitions(-DHAVE_MBEDTLS) + else(MBEDTLS_FOUND) + message(FATAL_ERROR "Either PolarSSL or mbedTLS are required to build srsRAN") + endif (MBEDTLS_FOUND) +endif(POLARSSL_FOUND) + +# Hard-SIM support +if(ENABLE_HARDSIM) + find_package(PCSCLite) + if (PCSCLITE_FOUND) + message(STATUS "Building with PCSC support.") + add_definitions(-DHAVE_PCSC) + set(HAVE_PCSC TRUE) + include_directories(${PCSCLITE_INCLUDE_DIR}) + #link_directories(${PCSCLITE_LIBRARIES}) + endif (PCSCLITE_FOUND) +endif(ENABLE_HARDSIM) + +# UHD +if(ENABLE_UHD) + find_package(UHD) + if(UHD_FOUND) + include_directories(${UHD_INCLUDE_DIRS}) + link_directories(${UHD_LIBRARY_DIRS}) + endif(UHD_FOUND) +endif(ENABLE_UHD) + +# SKIQ +if (ENABLE_SKIQ) + find_package(SKIQ) + if(SKIQ_FOUND) + include_directories(${SKIQ_INCLUDE_DIRS}) + link_directories(${SKIQ_LIBRARY_DIRS}) + endif(SKIQ_FOUND) +endif (ENABLE_SKIQ) + +# BladeRF +if(ENABLE_BLADERF) + find_package(bladeRF) + if(BLADERF_FOUND) + include_directories(${BLADERF_INCLUDE_DIRS}) + link_directories(${BLADERF_LIBRARY_DIRS}) + endif(BLADERF_FOUND) +endif(ENABLE_BLADERF) + +# Soapy +if(ENABLE_SOAPYSDR) + find_package(SoapySDR) + if(SOAPYSDR_FOUND) + include_directories(${SOAPYSDR_INCLUDE_DIRS}) + link_directories(${SOAPYSDR_LIBRARY_DIRS}) + endif(SOAPYSDR_FOUND) +endif(ENABLE_SOAPYSDR) + +# ZeroMQ +if(ENABLE_ZEROMQ) + find_package(ZeroMQ) + if(ZEROMQ_FOUND) + include_directories(${ZEROMQ_INCLUDE_DIRS}) + link_directories(${ZEROMQ_LIBRARY_DIRS}) + endif(ZEROMQ_FOUND) +endif(ENABLE_ZEROMQ) + +# TimeProf +if(ENABLE_TIMEPROF) + add_definitions(-DENABLE_TIMEPROF) +endif(ENABLE_TIMEPROF) + +if(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND OR SKIQ_FOUND) + set(RF_FOUND TRUE CACHE INTERNAL "RF frontend found") +else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND OR SKIQ_FOUND) + set(RF_FOUND FALSE CACHE INTERNAL "RF frontend found") + add_definitions(-DDISABLE_RF) +endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND OR ZEROMQ_FOUND OR SKIQ_FOUND) + +# Boost +if(BUILD_STATIC) + set(Boost_USE_STATIC_LIBS ON) +endif(BUILD_STATIC) + +set(BOOST_REQUIRED_COMPONENTS + program_options +) +if(UNIX AND EXISTS "/usr/lib64") + list(APPEND BOOST_LIBRARYDIR "/usr/lib64") #fedora 64-bit fix +endif(UNIX AND EXISTS "/usr/lib64") +set(Boost_ADDITIONAL_VERSIONS + "1.35.0" "1.35" "1.36.0" "1.36" "1.37.0" "1.37" "1.38.0" "1.38" "1.39.0" "1.39" + "1.40.0" "1.40" "1.41.0" "1.41" "1.42.0" "1.42" "1.43.0" "1.43" "1.44.0" "1.44" + "1.45.0" "1.45" "1.46.0" "1.46" "1.47.0" "1.47" "1.48.0" "1.48" "1.49.0" "1.49" + "1.50.0" "1.50" "1.51.0" "1.51" "1.52.0" "1.52" "1.53.0" "1.53" "1.54.0" "1.54" + "1.55.0" "1.55" "1.56.0" "1.56" "1.57.0" "1.57" "1.58.0" "1.58" "1.59.0" "1.59" + "1.60.0" "1.60" "1.61.0" "1.61" "1.62.0" "1.62" "1.63.0" "1.63" "1.64.0" "1.64" + "1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69" +) +find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS}) + +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) + link_directories(${Boost_LIBRARY_DIRS}) +else(Boost_FOUND) + message(FATAL_ERROR "Boost required to build srsRAN") +endif (Boost_FOUND) + +# srsGUI +if(ENABLE_GUI) + find_package(SRSGUI) + if(SRSGUI_FOUND) + add_definitions(-DENABLE_GUI) + include_directories(${SRSGUI_INCLUDE_DIRS}) + link_directories(${SRSGUI_LIBRARY_DIRS}) + endif(SRSGUI_FOUND) +endif(ENABLE_GUI) + +if (ENABLE_TTCN3) + find_package(RapidJSON REQUIRED) + add_definitions(-DENABLE_TTCN3) + include_directories(${RAPIDJSON_INCLUDE_DIRS}) + link_directories(${RAPIDJSON_LIBRARY_DIRS}) + message(STATUS "Building with TTCN3 binaries") +endif (ENABLE_TTCN3) + +# Backward-cpp +find_package(Backward) +if(Backward_FOUND) + if(BACKWARD_HAS_EXTERNAL_LIBRARIES) + add_definitions(-DHAVE_BACKWARD) + message(STATUS "Building with backward-cpp support") + else (BACKWARD_HAS_EXTERNAL_LIBRARIES) + message(STATUS "Backward-cpp found, but external libraries are missing.") + endif() +endif() + +######################################################################## +# Install Dirs +######################################################################## +if (NOT CMAKE_INSTALL_LIBDIR) + include(GNUInstallDirs) +endif (NOT CMAKE_INSTALL_LIBDIR) + +# Fall back to just "lib" if the item provided by GNUInstallDirs doesn't exist +if (NOT EXISTS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") + message(STATUS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} does not exist. Defaulting install location to ${CMAKE_INSTALL_PREFIX}/lib.") + set(CMAKE_INSTALL_LIBDIR lib) +endif() + +set(RUNTIME_DIR bin) +set(LIBRARY_DIR ${CMAKE_INSTALL_LIBDIR}) +set(INCLUDE_DIR include) +set(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}") +set(DATA_DIR share/${CPACK_PACKAGE_NAME}) + +# Auto-generate config install helper and mark for installation +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/modules/SRSRAN_install_configs.sh.in + ${CMAKE_BINARY_DIR}/srsran_install_configs.sh +) +install(PROGRAMS ${CMAKE_BINARY_DIR}/srsran_install_configs.sh DESTINATION ${RUNTIME_DIR}) + +# Disables the project to build when calling "make install" +set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY TRUE) + +######################################################################## +# Compiler specific setup +######################################################################## +macro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have) + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(${flag} ${have}) + if(${have}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") + endif(${have}) +endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE) + +macro(ADD_C_COMPILER_FLAG_IF_AVAILABLE flag have) + include(CheckCCompilerFlag) + check_c_compiler_flag(${flag} ${have}) + if(${have}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}") + endif(${have}) +endmacro(ADD_C_COMPILER_FLAG_IF_AVAILABLE) + +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-comment -Wno-reorder -Wno-unused-variable -Wtype-limits -std=c++11 -fno-strict-aliasing") + + ADD_C_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-Wno-unused-but-set-variable" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) + + if (AUTO_DETECT_ISA) + find_package(SSE) + endif (AUTO_DETECT_ISA) + + ADD_C_COMPILER_FLAG_IF_AVAILABLE("-march=${GCC_ARCH}" HAVE_MARCH_${GCC_ARCH}) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-march=${GCC_ARCH}" HAVE_MARCH_${GCC_ARCH}) + + if (HAVE_AVX2) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -mavx2 -DLV_HAVE_AVX2 -DLV_HAVE_AVX -DLV_HAVE_SSE") + else (HAVE_AVX2) + if(HAVE_AVX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") + elseif(HAVE_SSE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") + endif(HAVE_AVX) + endif (HAVE_AVX2) + + # Do not hide symbols in debug mode so backtraces can display function info. + if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if(NOT WIN32) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_CXX) + endif(NOT WIN32) + endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + if(FORCE_32BIT) + ADD_C_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-m32" HAVE_WNO_UNUSED_BUT_SET_VARIABLE) + set(CMAKE_SHARED_LINKER_FLAGS "-m32") + endif(FORCE_32BIT) + +endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + +ADD_C_COMPILER_FLAG_IF_AVAILABLE("-Werror=incompatible-pointer-types" HAVE_ERROR_INCOMPATIBLE) + +if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-comment -Wno-write-strings -Wno-unused-result -Wformat -Wmissing-field-initializers -Wtype-limits -std=c99 -fno-strict-aliasing -D_GNU_SOURCE") + + if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -O0 -DDEBUG_MODE -DBUILD_TYPE_DEBUG") + else(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -DBUILD_TYPE_RELWITHDEBINFO") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -DBUILD_TYPE_RELWITHDEBINFO") + else(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fno-trapping-math -fno-math-errno -DBUILD_TYPE_RELEASE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fno-trapping-math -fno-math-errno -DBUILD_TYPE_RELEASE") + if(BUILD_WITH_LTO) + ADD_C_COMPILER_FLAG_IF_AVAILABLE(-flto HAVE_FLTO) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-flto HAVE_FLTO) + endif(BUILD_WITH_LTO) + endif(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") + endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + if (USE_LTE_RATES) + message(STATUS "Using standard LTE sampling rates") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFORCE_STANDARD_RATE") + endif (USE_LTE_RATES) + + if (AUTO_DETECT_ISA) + find_package(SSE) + endif (AUTO_DETECT_ISA) + if (HAVE_AVX2) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -mavx2 -DLV_HAVE_AVX2 -DLV_HAVE_AVX -DLV_HAVE_SSE") + else (HAVE_AVX2) + if(HAVE_AVX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -mavx -DLV_HAVE_AVX -DLV_HAVE_SSE") + elseif(HAVE_SSE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -msse4.1 -DLV_HAVE_SSE") + endif(HAVE_AVX) + endif (HAVE_AVX2) + + if (HAVE_FMA) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfma -DLV_HAVE_FMA") + endif (HAVE_FMA) + + if (HAVE_AVX512) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx512f -mavx512cd -mavx512bw -mavx512dq -DLV_HAVE_AVX512") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx512f -mavx512cd -mavx512bw -mavx512dq -DLV_HAVE_AVX512") + endif(HAVE_AVX512) + + if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if(HAVE_SSE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -funroll-loops") + endif(HAVE_SSE) + endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DIS_ARM -DHAVE_NEON") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIS_ARM") + message(STATUS "Detected ARM processor") + set(HAVE_NEON "True") + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(HAVE_NEONv8 "True") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_NEONv8") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_NEONv8") + endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard -mfpu=neon") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfloat-abi=hard -mfpu=neon") + endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") + else(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(HAVE_NEON "False") + endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + set(CMAKE_REQUIRED_FLAGS ${CMAKE_C_FLAGS}) + + if(NOT HAVE_SSE AND NOT HAVE_NEON AND NOT DISABLE_SIMD) + message(FATAL_ERROR "no SIMD instructions found") + endif(NOT HAVE_SSE AND NOT HAVE_NEON AND NOT DISABLE_SIMD) + + # Do not hide symbols in debug mode so backtraces can display function info. + if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + if(NOT WIN32) + ADD_C_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_C) + endif(NOT WIN32) + endif(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug") + + if ((ENABLE_ASAN AND ENABLE_MSAN) OR (ENABLE_ASAN AND ENABLE_TSAN) OR (ENABLE_MSAN AND ENABLE_TSAN)) + message(FATAL_ERROR "ASAN, MSAN and TSAN cannot be enabled at the same time.") + endif () + + if (ENABLE_ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + endif (ENABLE_ASAN) + + if (ENABLE_TSAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -DHAVE_TSAN") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + endif (ENABLE_TSAN) + + if (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins -fPIE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins -fPIE") + endif (ENABLE_MSAN AND CMAKE_C_COMPILER_ID MATCHES "Clang") + + if (ENABLE_GCOV) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + endif (ENABLE_GCOV) + +endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # The following is needed for weak linking to work under OS X + set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + +# Add colored output when using the Ninja generator +if("Ninja" STREQUAL ${CMAKE_GENERATOR}) + ADD_C_COMPILER_FLAG_IF_AVAILABLE("-fdiagnostics-color=always" HAVE_DIAGNOSTIC_COLOR_C) + ADD_CXX_COMPILER_FLAG_IF_AVAILABLE("-fdiagnostics-color=always" HAVE_DIAGNOSTIC_COLOR_CXX) +endif() + +# Add -Werror to C/C++ flags for newer compilers +if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") +endif() + +if(CMAKE_C_COMPILER_ID MATCHES "GNU") + # Increase inlining limit to allow gcc compilation on e.g. RPi2 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --param large-function-growth=1600") +endif(CMAKE_C_COMPILER_ID MATCHES "GNU") + +if (EXTRA_TERM_TIMEOUT_S) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSRSRAN_TERM_TIMEOUT_S=${EXTRA_TERM_TIMEOUT_S}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSRSRAN_TERM_TIMEOUT_S=${EXTRA_TERM_TIMEOUT_S}") +endif (EXTRA_TERM_TIMEOUT_S) + +message(STATUS "CMAKE_C_FLAGS is ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_CXX_FLAGS is ${CMAKE_CXX_FLAGS}") + + +######################################################################## +# clang-tidy check +######################################################################## +if(ENABLE_TIDY) + find_program( + CLANG_TIDY_BIN + NAMES "clang-tidy" + DOC "Path to clang-tidy executable" + ) + if(NOT CLANG_TIDY_BIN) + message(STATUS "clang-tidy not found.") + else() + message(STATUS "clang-tidy found: ${CLANG_TIDY_BIN}") + set(DO_CLANG_TIDY "${CLANG_TIDY_BIN}" "-checks=*,-clang-analyzer-alpha.*,-modernize-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-bounds-constant-array-index") + endif() +endif(ENABLE_TIDY) + +######################################################################## +# Create uninstall targets +######################################################################## +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + +add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + +######################################################################## +# Create optional target to build osmo-gsm-tester trial +######################################################################## +add_custom_target(trial + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_trial.sh) + +######################################################################## +# Add -fPIC property to all targets +######################################################################## +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +######################################################################## +# Print summary +######################################################################## +message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") +message(STATUS "Building for version: ${VERSION}") + +######################################################################## +# Ctest function helpers +######################################################################## + +function(add_lte_test) + add_test(${ARGN}) + set(TNAME ${ARGV0}) + if(${TNAME} STREQUAL NAME) + set(TNAME ${ARGV1}) + endif() + set_tests_properties(${TNAME} PROPERTIES LABELS "lte;${CTEST_LABELS}") +endfunction() + +function(add_nr_test) + add_test(${ARGN}) + set(TNAME ${ARGV0}) + if(${TNAME} STREQUAL NAME) + set(TNAME ${ARGV1}) + endif() + set_tests_properties(${TNAME} PROPERTIES LABELS "nr;${CTEST_LABELS}") +endfunction() + +function(add_nr_advanced_test) + if (NOT ${ENABLE_ALL_TEST}) + return() + endif() + add_test(${ARGN}) + set(TNAME ${ARGV0}) + if(${TNAME} STREQUAL NAME) + set(TNAME ${ARGV1}) + endif() + set_tests_properties(${TNAME} PROPERTIES LABELS "nr;${CTEST_LABELS}") +endfunction() + +######################################################################## +# Add general includes and dependencies +######################################################################## +include_directories(${PROJECT_BINARY_DIR}/lib/include) +include_directories(${PROJECT_SOURCE_DIR}/lib/include) + +######################################################################## +# Add headers to cmake project (useful for IDEs) +######################################################################## +set(HEADERS_ALL "") +file(GLOB headers *) +foreach(_header ${headers}) + if(IS_DIRECTORY ${_header}) + file(GLOB_RECURSE tmp "${_header}/*.h") + list(APPEND HEADERS_ALL ${tmp}) + endif(IS_DIRECTORY ${_header}) +endforeach() +add_custom_target(add_srsran_headers SOURCES ${HEADERS_ALL}) + +######################################################################## +# Add the subdirectories +######################################################################## +add_subdirectory(lib) + +if(RF_FOUND) + if(ENABLE_SRSUE) + message(STATUS "Building with srsUE") + add_subdirectory(srsue) + else(ENABLE_SRSUE) + message(STATUS "srsUE build disabled") + endif(ENABLE_SRSUE) + + if(ENABLE_SRSENB) + message(STATUS "Building with srsENB") + add_subdirectory(srsenb) + else(ENABLE_SRSENB) + message(STATUS "srsENB build disabled") + endif(ENABLE_SRSENB) +else(RF_FOUND) + message(STATUS "srsUE and srsENB builds disabled due to missing RF driver") +endif(RF_FOUND) + +if(ENABLE_SRSEPC) + message(STATUS "Building with srsEPC") + add_subdirectory(srsepc) +else(ENABLE_SRSEPC) + message(STATUS "srsEPC build disabled") +endif(ENABLE_SRSEPC) + +add_subdirectory(test) diff --git a/srsRAN_4G_mirror/COPYRIGHT b/srsRAN_4G_mirror/COPYRIGHT new file mode 100644 index 0000000..7b6dc37 --- /dev/null +++ b/srsRAN_4G_mirror/COPYRIGHT @@ -0,0 +1,142 @@ +Files: * +Copyright: 2013-2021, Software Radio Systems Limited. +License: + + +The following files are used within srsRAN: + +Files: lib/src/phy/fec/viterbi37_port.c + lib/src/phy/fec/viterbi37_sse.c + lib/src/phy/fec/viterbi37_avx2.c + lib/src/phy/fec/viterbi37_neon.c + lib/src/phy/fec/viterbi37_avx2_16bit.c + lib/src/phy/fec/parity.c +Copyright: 2009, Phil Karn, KA9Q +License: LGPL-2.1 + +Files: srsue/src/upper/pcsc_usim.cc + srsue/hdr/upper/pcsc_usim.h +Copyright: 2002-2014, Jouni Malinen +License: BSD-3-clause + +Files: lib/include/srsran/asn1/liblte_common.h + lib/include/srsran/asn1/liblte_mme.h + lib/include/srsran/common/liblte_security.h + lib/src/asn1/liblte_common.cc + lib/src/asn1/liblte_mme.cc + lib/src/common/liblte_security.cc +Copyright: 2012-2014 Ben Wojtowicz +License: AGPL-3+ + +Files: lib/include/srsran/srslog/bundled/fmt/chrono.h + lib/include/srsran/srslog/bundled/fmt/color.h + lib/include/srsran/srslog/bundled/fmt/compile.h + lib/include/srsran/srslog/bundled/fmt/core.h + lib/include/srsran/srslog/bundled/fmt/format.h + lib/include/srsran/srslog/bundled/fmt/format-inl.h + lib/include/srsran/srslog/bundled/fmt/LICENSE.rst + lib/include/srsran/srslog/bundled/fmt/locale.h + lib/include/srsran/srslog/bundled/fmt/os.h + lib/include/srsran/srslog/bundled/fmt/ostream.h + lib/include/srsran/srslog/bundled/fmt/posix.h + lib/include/srsran/srslog/bundled/fmt/printf.h + lib/include/srsran/srslog/bundled/fmt/ranges.h + lib/src/srslog/bundled/fmt/format.cc + lib/src/srslog/bundled/fmt/os.cc +Copyright: 2012-2020, Victor Zverovich +License: MIT + +Files: lib/include/srsran/common/backward.hpp + cmake/modules/FindBackward.cmake +Copyright: 2013, Google Inc. +License: MIT + +Files: cmake/modules/CheckAtomic.cmake +Copyright: 2015, Charles J. Cliffe +License: MIT + +License: AGPL-3+ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + . + This program 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 Affero General Public License for more details. + . + On Debian systems, the complete text of the AGPL 3 can be found in + /usr/share/doc/srsran/LICENSE + + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + This library 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +License: MIT +Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, +portions of this Software are embedded into a machine-executable object +form of such source code, you may redistribute such embedded portions in +such object form without including the above copyright and permission notices. diff --git a/srsRAN_4G_mirror/CTestConfig.cmake b/srsRAN_4G_mirror/CTestConfig.cmake new file mode 100644 index 0000000..fe80d73 --- /dev/null +++ b/srsRAN_4G_mirror/CTestConfig.cmake @@ -0,0 +1,27 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +set(CTEST_PROJECT_NAME "srsRAN") +set(CTEST_NIGHTLY_START_TIME "00:00:00 GMT") +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=srsRAN") +set(CTEST_DROP_SITE_CDASH TRUE) +set(VALGRIND_COMMAND_OPTIONS "--error-exitcode=1 --trace-children=yes --leak-check=full --show-leak-kinds=all --track-origins=yes --show-reachable=yes --vex-guest-max-insns=25") diff --git a/srsRAN_4G_mirror/CTestCustom.cmake.in b/srsRAN_4G_mirror/CTestCustom.cmake.in new file mode 100644 index 0000000..bbd6beb --- /dev/null +++ b/srsRAN_4G_mirror/CTestCustom.cmake.in @@ -0,0 +1,5 @@ +SET(CTEST_CUSTOM_MEMCHECK_IGNORE +# Ignore these to, they take too long + ue_phy_test +) + diff --git a/srsRAN_4G_mirror/LICENSE b/srsRAN_4G_mirror/LICENSE new file mode 100644 index 0000000..dba13ed --- /dev/null +++ b/srsRAN_4G_mirror/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/srsRAN_4G_mirror/README.md b/srsRAN_4G_mirror/README.md new file mode 100644 index 0000000..90659b5 --- /dev/null +++ b/srsRAN_4G_mirror/README.md @@ -0,0 +1,24 @@ +srsRAN +====== + +[![Build Status](https://app.travis-ci.com/srsran/srsRAN.svg?branch=master)](https://app.travis-ci.com/github/srsran/srsRAN) +[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/srsran/srsRAN.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/srsran/srsRAN/context:cpp) +[![Coverity](https://scan.coverity.com/projects/23045/badge.svg)](https://scan.coverity.com/projects/srsran) + +srsRAN is a 4G/5G software radio suite developed by [SRS](http://www.srs.io). + +See the [srsRAN project pages](https://www.srsran.com) for information, guides and project news. + +The srsRAN suite includes: + * srsUE - a full-stack SDR 4G/5G-NSA UE application (5G-SA coming soon) + * srsENB - a full-stack SDR 4G/5G-NSA eNodeB application (5G-SA coming soon) + * srsEPC - a light-weight 4G core network implementation with MME, HSS and S/P-GW + +For application features, build instructions and user guides see the [srsRAN documentation](https://docs.srsran.com). + +For license details, see LICENSE file. + +Support +======= + +Mailing list: https://lists.srsran.com/mailman/listinfo/srsran-users diff --git a/srsRAN_4G_mirror/build_trial.sh b/srsRAN_4G_mirror/build_trial.sh new file mode 100755 index 0000000..1741214 --- /dev/null +++ b/srsRAN_4G_mirror/build_trial.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +rm -rf sysroot && mkdir sysroot +cmake -DCMAKE_INSTALL_PREFIX="sysroot/" ../ +make install +this="$(date +%Y-%m-%d_%H_%M_%S)" +trialdir="srsran_trial_${this}" +tar="srsran.build-${this}.tgz" +mkdir ${trialdir} +tar czf "${trialdir}/$tar" -C "sysroot" . +md5sum "${trialdir}/$tar" >>${trialdir}/checksums.md5 + +echo "Built ${trialdir}" + diff --git a/srsRAN_4G_mirror/cmake/modules/CheckAtomic.cmake b/srsRAN_4G_mirror/cmake/modules/CheckAtomic.cmake new file mode 100644 index 0000000..8a58bf2 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/CheckAtomic.cmake @@ -0,0 +1,104 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# Adopted from https://github.com/pothosware/SoapyRTLSDR +# Copyright: 2015, Charles J. Cliffe +# License: MIT + +# - Try to find if atomics need -latomic linking +# Once done this will define +# HAVE_CXX_ATOMICS_WITHOUT_LIB - Wether atomic types work without -latomic +# HAVE_CXX_ATOMICS64_WITHOUT_LIB - Wether 64 bit atomic types work without -latomic + +INCLUDE(CheckCXXSourceCompiles) +INCLUDE(CheckLibraryExists) + +# Sometimes linking against libatomic is required for atomic ops, if +# the platform doesn't support lock-free atomics. + +function(check_working_cxx_atomics varname) +set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") +CHECK_CXX_SOURCE_COMPILES(" +#include +std::atomic x; +int main() { +return std::atomic_is_lock_free(&x); +} +" ${varname}) +set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics) + +function(check_working_cxx_atomics64 varname) +set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) +set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") +CHECK_CXX_SOURCE_COMPILES(" +#include +#include +std::atomic x (0); +int main() { +uint64_t i = x.load(std::memory_order_relaxed); +return std::atomic_is_lock_free(&x); +} +" ${varname}) +set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics64) + +# Check for atomic operations. +if(MSVC) + # This isn't necessary on MSVC. + set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) +else() + # First check if atomics work without the library. + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) +endif() + +# If not, check if the library exists, and atomics work with it. +if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) + check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) + if(NOT HAVE_LIBATOMIC) + message(STATUS "Host compiler appears to require libatomic, but cannot locate it.") + endif() + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() +endif() + +# Check for 64 bit atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) +else() + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) +endif() + +# If not, check if the library exists, and atomics work with it. +if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + check_library_exists(atomic __atomic_load_8 "" HAVE_LIBATOMIC64) + if(NOT HAVE_LIBATOMIC64) + message(STATUS "Host compiler appears to require libatomic, but cannot locate it.") + endif() + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() +endif() \ No newline at end of file diff --git a/srsRAN_4G_mirror/cmake/modules/CheckCSourceRuns.cmake b/srsRAN_4G_mirror/cmake/modules/CheckCSourceRuns.cmake new file mode 100644 index 0000000..4261a46 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/CheckCSourceRuns.cmake @@ -0,0 +1,105 @@ +#.rst: +# CheckCSourceRuns +# ---------------- +# +# Check if the given C source code compiles and runs. +# +# CHECK_C_SOURCE_RUNS( ) +# +# :: +# +# - source code to try to compile +# - variable to store the result +# (1 for success, empty for failure) +# Will be created as an internal cache variable. +# +# The following variables may be set before calling this macro to modify +# the way the check is run: +# +# :: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link +# CMAKE_REQUIRED_QUIET = execute quietly without messages + +#============================================================================= +# Copyright 2006-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +macro(CHECK_C_SOURCE_RUNS SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_C_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_run(${VAR}_EXITCODE ${VAR}_COMPILED + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} + "${CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}" + COMPILE_OUTPUT_VARIABLE OUTPUT) + # if it did not compile make the return value fail code of 1 + if(NOT ${VAR}_COMPILED) + set(${VAR}_EXITCODE 1) + endif() + # if the return value was 0 then it worked + if("${${VAR}_EXITCODE}" EQUAL 0) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing C SOURCE FILE Test ${VAR} succeeded with the following output:\n" + "${OUTPUT}\n" + "Return value: ${${VAR}}\n" + "Source file was:\n${SOURCE}\n") + else() + if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") + set(${VAR} "${${VAR}_EXITCODE}") + else() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + endif() + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n" + "${OUTPUT}\n" + "Return value: ${${VAR}_EXITCODE}\n" + "Source file was:\n${SOURCE}\n") + + endif() + endif() +endmacro() + diff --git a/srsRAN_4G_mirror/cmake/modules/CheckFunctionExists.c b/srsRAN_4G_mirror/cmake/modules/CheckFunctionExists.c new file mode 100644 index 0000000..0cd33af --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/CheckFunctionExists.c @@ -0,0 +1,47 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifdef CHECK_FUNCTION_EXISTS + +char CHECK_FUNCTION_EXISTS(); +#ifdef __CLASSIC_C__ +int main() +{ + int ac; + char* av[]; +#else +int main(int ac, char* av[]) +{ + +#endif + float ac2 = sqrtf(rand()); + CHECK_FUNCTION_EXISTS(); + if (ac2 * ac > 1000) { + return *av[0]; + } + return 0; +} + +#else /* CHECK_FUNCTION_EXISTS */ + +#error "CHECK_FUNCTION_EXISTS has to specify the function" + +#endif /* CHECK_FUNCTION_EXISTS */ diff --git a/srsRAN_4G_mirror/cmake/modules/CheckFunctionExistsMath.cmake b/srsRAN_4G_mirror/cmake/modules/CheckFunctionExistsMath.cmake new file mode 100644 index 0000000..82f371a --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/CheckFunctionExistsMath.cmake @@ -0,0 +1,67 @@ +# - Check if a C function can be linked +# CHECK_FUNCTION_EXISTS( ) +# +# Check that the is provided by libraries on the system and +# store the result in a . This does not verify that any +# system header file declares the function, only that it can be found +# at link time (considure using CheckSymbolExists). +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link + +#============================================================================= +# Copyright 2002-2011 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE) + IF(${VARIABLE} MATCHES "^${VARIABLE}$") + SET(MACRO_CHECK_FUNCTION_DEFINITIONS + "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") + MESSAGE(STATUS "Looking for ${FUNCTION}") + IF(CMAKE_REQUIRED_LIBRARIES) + SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") + ELSE(CMAKE_REQUIRED_LIBRARIES) + SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES) + ENDIF(CMAKE_REQUIRED_LIBRARIES) + IF(CMAKE_REQUIRED_INCLUDES) + SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + ELSE(CMAKE_REQUIRED_INCLUDES) + SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES) + ENDIF(CMAKE_REQUIRED_INCLUDES) + TRY_COMPILE(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/cmake/modules/CheckFunctionExists.c + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}" + "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + IF(${VARIABLE}) + SET(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}") + MESSAGE(STATUS "Looking for ${FUNCTION} - found") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the function ${FUNCTION} exists passed with the following output:\n" + "${OUTPUT}\n\n") + ELSE(${VARIABLE}) + MESSAGE(STATUS "Looking for ${FUNCTION} - not found") + SET(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the function ${FUNCTION} exists failed with the following output:\n" + "${OUTPUT}\n\n") + ENDIF(${VARIABLE}) + ENDIF(${VARIABLE} MATCHES "^${VARIABLE}$") +ENDMACRO(CHECK_FUNCTION_EXISTS_MATH) diff --git a/srsRAN_4G_mirror/cmake/modules/FindBackward.cmake b/srsRAN_4G_mirror/cmake/modules/FindBackward.cmake new file mode 100644 index 0000000..025383f --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindBackward.cmake @@ -0,0 +1,243 @@ +# +# BackwardMacros.cmake +# Copyright 2013 Google Inc. All Rights Reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +############################################################################### +# OPTIONS +############################################################################### + +if(POLICY CMP0011) + cmake_policy(SET CMP0011 NEW) + cmake_policy(SET CMP0012 NEW) +endif() + +set(STACK_WALKING_UNWIND TRUE CACHE BOOL + "Use compiler's unwind API") +set(STACK_WALKING_BACKTRACE FALSE CACHE BOOL + "Use backtrace from (e)glibc for stack walking") +set(STACK_WALKING_LIBUNWIND FALSE CACHE BOOL + "Use libunwind for stack walking") + +set(STACK_DETAILS_AUTO_DETECT TRUE CACHE BOOL + "Auto detect backward's stack details dependencies") + +set(STACK_DETAILS_BACKTRACE_SYMBOL FALSE CACHE BOOL + "Use backtrace from (e)glibc for symbols resolution") +set(STACK_DETAILS_DW FALSE CACHE BOOL + "Use libdw to read debug info") +set(STACK_DETAILS_BFD FALSE CACHE BOOL + "Use libbfd to read debug info") +set(STACK_DETAILS_DWARF FALSE CACHE BOOL + "Use libdwarf/libelf to read debug info") + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT DEFINED BACKWARD_TESTS) + # If this is a top level CMake project, we most lixely want the tests + set(BACKWARD_TESTS ON CACHE BOOL "Enable tests") +else() + set(BACKWARD_TESTS OFF CACHE BOOL "Enable tests") +endif() +############################################################################### +# CONFIGS +############################################################################### +include(FindPackageHandleStandardArgs) + +if (STACK_WALKING_LIBUNWIND) + # libunwind works on the macOS without having to add special include + # paths or libraries + if (NOT APPLE) + find_path(LIBUNWIND_INCLUDE_DIR NAMES "libunwind.h") + find_library(LIBUNWIND_LIBRARY unwind) + + if (LIBUNWIND_LIBRARY) + include(CheckSymbolExists) + check_symbol_exists(UNW_INIT_SIGNAL_FRAME libunwind.h HAVE_UNW_INIT_SIGNAL_FRAME) + if (NOT HAVE_UNW_INIT_SIGNAL_FRAME) + message(STATUS "libunwind does not support unwinding from signal handler frames") + endif() + endif() + + set(LIBUNWIND_INCLUDE_DIRS ${LIBUNWIND_INCLUDE_DIR}) + set(LIBDWARF_LIBRARIES ${LIBUNWIND_LIBRARY}) + find_package_handle_standard_args(libunwind DEFAULT_MSG LIBUNWIND_LIBRARY LIBUNWIND_INCLUDE_DIR) + mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARY) + list(APPEND _BACKWARD_LIBRARIES ${LIBUNWIND_LIBRARY}) + endif() + + # Disable other unwinders if libunwind is found + set(STACK_WALKING_UNWIND FALSE) + set(STACK_WALKING_BACKTRACE FALSE) +endif() + +if (STACK_DETAILS_AUTO_DETECT) + if(NOT CMAKE_VERSION VERSION_LESS 3.17) + set(_name_mismatched_arg NAME_MISMATCHED) + endif() + # find libdw + find_path(LIBDW_INCLUDE_DIR NAMES "elfutils/libdw.h" "elfutils/libdwfl.h") + find_library(LIBDW_LIBRARY dw) + set(LIBDW_INCLUDE_DIRS ${LIBDW_INCLUDE_DIR} ) + set(LIBDW_LIBRARIES ${LIBDW_LIBRARY} ) + find_package_handle_standard_args(libdw REQUIRED_VARS + LIBDW_LIBRARY LIBDW_INCLUDE_DIR ${_name_mismatched_arg}) + mark_as_advanced(LIBDW_INCLUDE_DIR LIBDW_LIBRARY) + + # find libbfd + find_path(LIBBFD_INCLUDE_DIR NAMES "bfd.h") + find_path(LIBDL_INCLUDE_DIR NAMES "dlfcn.h") + find_library(LIBBFD_LIBRARY bfd) + find_library(LIBDL_LIBRARY dl) + set(LIBBFD_INCLUDE_DIRS ${LIBBFD_INCLUDE_DIR} ${LIBDL_INCLUDE_DIR}) + set(LIBBFD_LIBRARIES ${LIBBFD_LIBRARY} ${LIBDL_LIBRARY}) + find_package_handle_standard_args(libbfd REQUIRED_VARS + LIBBFD_LIBRARY LIBBFD_INCLUDE_DIR + LIBDL_LIBRARY LIBDL_INCLUDE_DIR ${_name_mismatched_arg}) + mark_as_advanced(LIBBFD_INCLUDE_DIR LIBBFD_LIBRARY + LIBDL_INCLUDE_DIR LIBDL_LIBRARY) + # find libdwarf + find_path(LIBDWARF_INCLUDE_DIR NAMES "libdwarf.h" PATH_SUFFIXES libdwarf) + find_path(LIBELF_INCLUDE_DIR NAMES "libelf.h") + find_path(LIBDL_INCLUDE_DIR NAMES "dlfcn.h") + find_library(LIBDWARF_LIBRARY dwarf) + find_library(LIBELF_LIBRARY elf) + find_library(LIBDL_LIBRARY dl) + set(LIBDWARF_INCLUDE_DIRS ${LIBDWARF_INCLUDE_DIR} ${LIBELF_INCLUDE_DIR} ${LIBDL_INCLUDE_DIR}) + set(LIBDWARF_LIBRARIES ${LIBDWARF_LIBRARY} ${LIBELF_LIBRARY} ${LIBDL_LIBRARY}) + find_package_handle_standard_args(libdwarf REQUIRED_VARS + LIBDWARF_LIBRARY LIBDWARF_INCLUDE_DIR + LIBELF_LIBRARY LIBELF_INCLUDE_DIR + LIBDL_LIBRARY LIBDL_INCLUDE_DIR ${_name_mismatched_arg}) + mark_as_advanced(LIBDWARF_INCLUDE_DIR LIBDWARF_LIBRARY + LIBELF_INCLUDE_DIR LIBELF_LIBRARY + LIBDL_INCLUDE_DIR LIBDL_LIBRARY) + + if (LIBDW_FOUND) + LIST(APPEND _BACKWARD_INCLUDE_DIRS ${LIBDW_INCLUDE_DIRS}) + LIST(APPEND _BACKWARD_LIBRARIES ${LIBDW_LIBRARIES}) + set(STACK_DETAILS_DW TRUE) + set(STACK_DETAILS_BFD FALSE) + set(STACK_DETAILS_DWARF FALSE) + set(STACK_DETAILS_BACKTRACE_SYMBOL FALSE) + elseif(LIBBFD_FOUND) + LIST(APPEND _BACKWARD_INCLUDE_DIRS ${LIBBFD_INCLUDE_DIRS}) + LIST(APPEND _BACKWARD_LIBRARIES ${LIBBFD_LIBRARIES}) + + # If we attempt to link against static bfd, make sure to link its dependencies, too + get_filename_component(bfd_lib_ext "${LIBBFD_LIBRARY}" EXT) + if (bfd_lib_ext STREQUAL "${CMAKE_STATIC_LIBRARY_SUFFIX}") + list(APPEND _BACKWARD_LIBRARIES iberty z) + endif() + + set(STACK_DETAILS_DW FALSE) + set(STACK_DETAILS_BFD TRUE) + set(STACK_DETAILS_DWARF FALSE) + set(STACK_DETAILS_BACKTRACE_SYMBOL FALSE) + elseif(LIBDWARF_FOUND) + LIST(APPEND _BACKWARD_INCLUDE_DIRS ${LIBDWARF_INCLUDE_DIRS}) + LIST(APPEND _BACKWARD_LIBRARIES ${LIBDWARF_LIBRARIES}) + + set(STACK_DETAILS_DW FALSE) + set(STACK_DETAILS_BFD FALSE) + set(STACK_DETAILS_DWARF TRUE) + set(STACK_DETAILS_BACKTRACE_SYMBOL FALSE) + else() + set(STACK_DETAILS_DW FALSE) + set(STACK_DETAILS_BFD FALSE) + set(STACK_DETAILS_DWARF FALSE) + set(STACK_DETAILS_BACKTRACE_SYMBOL TRUE) + endif() +else() + if (STACK_DETAILS_DW) + LIST(APPEND _BACKWARD_LIBRARIES dw) + endif() + + if (STACK_DETAILS_BFD) + LIST(APPEND _BACKWARD_LIBRARIES bfd dl) + endif() + + if (STACK_DETAILS_DWARF) + LIST(APPEND _BACKWARD_LIBRARIES dwarf elf) + endif() +endif() + +macro(map_definitions var_prefix define_prefix) + foreach(def ${ARGN}) + if (${var_prefix}${def}) + LIST(APPEND _BACKWARD_DEFINITIONS "${define_prefix}${def}=1") + else() + LIST(APPEND _BACKWARD_DEFINITIONS "${define_prefix}${def}=0") + endif() + endforeach() +endmacro() + +if (NOT _BACKWARD_DEFINITIONS) + map_definitions("STACK_WALKING_" "BACKWARD_HAS_" UNWIND LIBUNWIND BACKTRACE) + map_definitions("STACK_DETAILS_" "BACKWARD_HAS_" BACKTRACE_SYMBOL DW BFD DWARF) +endif() + +set(BACKWARD_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}") + +set(BACKWARD_HAS_EXTERNAL_LIBRARIES FALSE) +set(FIND_PACKAGE_REQUIRED_VARS BACKWARD_INCLUDE_DIR) +if(DEFINED _BACKWARD_LIBRARIES) + set(BACKWARD_HAS_EXTERNAL_LIBRARIES TRUE) + list(APPEND FIND_PACKAGE_REQUIRED_VARS _BACKWARD_LIBRARIES) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Backward REQUIRED_VARS ${FIND_PACKAGE_REQUIRED_VARS} +) +list(APPEND _BACKWARD_INCLUDE_DIRS ${BACKWARD_INCLUDE_DIR}) + +macro(add_backward target) + target_include_directories(${target} PRIVATE ${BACKWARD_INCLUDE_DIRS}) + set_property(TARGET ${target} APPEND PROPERTY COMPILE_DEFINITIONS ${BACKWARD_DEFINITIONS}) + set_property(TARGET ${target} APPEND PROPERTY LINK_LIBRARIES ${BACKWARD_LIBRARIES}) +endmacro() + +set(BACKWARD_INCLUDE_DIRS ${_BACKWARD_INCLUDE_DIRS} CACHE INTERNAL "_BACKWARD_INCLUDE_DIRS") +set(BACKWARD_DEFINITIONS ${_BACKWARD_DEFINITIONS} CACHE INTERNAL "BACKWARD_DEFINITIONS") +set(BACKWARD_LIBRARIES ${_BACKWARD_LIBRARIES} CACHE INTERNAL "BACKWARD_LIBRARIES") +mark_as_advanced(BACKWARD_INCLUDE_DIRS BACKWARD_DEFINITIONS BACKWARD_LIBRARIES) + +# Expand each definition in BACKWARD_DEFINITIONS to its own cmake var and export +# to outer scope +foreach(var ${BACKWARD_DEFINITIONS}) + string(REPLACE "=" ";" var_as_list ${var}) + list(GET var_as_list 0 var_name) + list(GET var_as_list 1 var_value) + set(${var_name} ${var_value}) + mark_as_advanced(${var_name}) + #message(STATUS "${var_name}=${var_value}") +endforeach() + +# Disabled for older CMake version (CentOS) +#if (NOT TARGET Backward::Backward) +# add_library(Backward::Backward INTERFACE IMPORTED) +# set_target_properties(Backward::Backward PROPERTIES +# INTERFACE_INCLUDE_DIRECTORIES "${BACKWARD_INCLUDE_DIRS}" +# INTERFACE_COMPILE_DEFINITIONS "${BACKWARD_DEFINITIONS}" +# ) +# if(BACKWARD_HAS_EXTERNAL_LIBRARIES) +# set_target_properties(Backward::Backward PROPERTIES +# INTERFACE_LINK_LIBRARIES "${BACKWARD_LIBRARIES}" +# ) +# endif() +#endif() diff --git a/srsRAN_4G_mirror/cmake/modules/FindFFTW3F.cmake b/srsRAN_4G_mirror/cmake/modules/FindFFTW3F.cmake new file mode 100644 index 0000000..c6a3ff7 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindFFTW3F.cmake @@ -0,0 +1,63 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find fftw3f - the single-precision version of FFTW3 +# Once done this will define +# FFTW3F_FOUND - System has fftw3f +# FFTW3F_INCLUDE_DIRS - The fftw3f include directories +# FFTW3F_LIBRARIES - The libraries needed to use fftw3f +# FFTW3F_DEFINITIONS - Compiler switches required for using fftw3f + +find_package(PkgConfig REQUIRED) +pkg_check_modules(PC_FFTW3F "fftw3f >= 3.0") +set(FFTW3F_DEFINITIONS ${PC_FFTW3F_CFLAGS_OTHER}) + +find_path(FFTW3F_INCLUDE_DIR + NAMES fftw3.h + HINTS ${PC_FFTW3F_INCLUDEDIR} ${PC_FFTW3F_INCLUDE_DIRS} $ENV{FFTW3_DIR}/include + PATHS /usr/local/include + /usr/include ) + +find_library(FFTW3F_STATIC_LIBRARY + NAMES fftw3f.a libfftw3f.a libfftw3f-3.a + HINTS ${PC_FFTW3F_LIBDIR} ${PC_FFTW3F_LIBRARY_DIRS} $ENV{FFTW3_DIR}/lib + PATHS /usr/local/lib + /usr/lib) + +find_library(FFTW3F_LIBRARY + NAMES fftw3f libfftw3f libfftw3f-3 + HINTS ${PC_FFTW3F_LIBDIR} ${PC_FFTW3F_LIBRARY_DIRS} $ENV{FFTW3_DIR}/lib + PATHS /usr/local/lib + /usr/lib) + +set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY} ) +set(FFTW3F_STATIC_LIBRARIES ${FFTW3F_STATIC_LIBRARY} ) +set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR} ) + +message(STATUS "FFTW3F LIBRARIES: " ${FFTW3F_LIBRARIES}) +message(STATUS "FFTW3F STATIC LIBRARIES: " ${FFTW3F_STATIC_LIBRARIES}) +message(STATUS "FFTW3F INCLUDE DIRS: " ${FFTW3F_INCLUDE_DIRS}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set FFTW3F_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(FFTW3F DEFAULT_MSG FFTW3F_LIBRARY FFTW3F_INCLUDE_DIR) + +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_STATIC_LIBRARY FFTW3F_LIBRARY ) diff --git a/srsRAN_4G_mirror/cmake/modules/FindLibConfig.cmake b/srsRAN_4G_mirror/cmake/modules/FindLibConfig.cmake new file mode 100644 index 0000000..d109c21 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindLibConfig.cmake @@ -0,0 +1,101 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# Find the CUnit includes and library +# +# This module defines +# LIBCONFIG_INCLUDE_DIR, where to find cppunit include files, etc. +# LIBCONFIG_LIBRARIES, the libraries to link against to use CppUnit. +# LIBCONFIG_STATIC_LIBRARIY_PATH +# LIBCONFIG_FOUND, If false, do not try to use CppUnit. + +# also defined, but not for general use are +# LIBCONFIG_LIBRARY, where to find the CUnit library. + +#MESSAGE("Searching for libconfig library") + +FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h + /usr/local/include + /usr/include + /usr/lib/x86_64-linux-gnu/ +) + +FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++ + /usr/local/include + /usr/include + /usr/lib/x86_64-linux-gnu/ +) + +FIND_LIBRARY(LIBCONFIG_LIBRARY config + /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu/ +) + +FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++ + /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu/ +) + +FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}" + /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu/ +) + +FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}" + /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu/ +) + + +IF(LIBCONFIG_INCLUDE_DIR) + IF(LIBCONFIG_LIBRARY) + SET(LIBCONFIG_FOUND TRUE) + SET(LIBCONFIG_LIBRARIES ${LIBCONFIG_LIBRARY}) + SET(LIBCONFIG_STATIC_LIBRARY_PATH ${LIBCONFIG_STATIC_LIBRARY}) + ENDIF(LIBCONFIG_LIBRARY) +ENDIF(LIBCONFIG_INCLUDE_DIR) + +IF(LIBCONFIGPP_INCLUDE_DIR) + IF(LIBCONFIGPP_LIBRARY) + SET(LIBCONFIGPP_FOUND TRUE) + SET(LIBCONFIGPP_LIBRARIES ${LIBCONFIGPP_LIBRARY}) + SET(LIBCONFIGPP_STATIC_LIBRARY_PATH ${LIBCONFIGPP_STATIC_LIBRARY}) + ENDIF(LIBCONFIGPP_LIBRARY) +ENDIF(LIBCONFIGPP_INCLUDE_DIR) + +IF (LIBCONFIGPP_FOUND) + IF (NOT LibConfig_FIND_QUIETLY) + MESSAGE(STATUS "Found LibConfig++: ${LIBCONFIGPP_LIBRARIES}" ) + MESSAGE(STATUS "static LibConfig++ path: ${LIBCONFIGPP_STATIC_LIBRARY_PATH}") + MESSAGE(STATUS "Found LibConfig: ${LIBCONFIG_LIBRARIES}") + MESSAGE(STATUS "static LibConfig path: ${LIBCONFIG_STATIC_LIBRARY_PATH}") + ENDIF (NOT LibConfig_FIND_QUIETLY) +ELSE (LIBCONFIGPP_FOUND) + IF (LibConfig_FIND_REQUIRED) + MESSAGE(SEND_ERROR "Could NOT find LibConfig") + ENDIF (LibConfig_FIND_REQUIRED) +ENDIF (LIBCONFIGPP_FOUND) + +MARK_AS_ADVANCED(LIBCONFIG_INCLUDE_DIR LIBCONFIG_LIBRARY LIBCONFIG_STATIC_LIBRARY) +MARK_AS_ADVANCED(LIBCONFIGPP_INCLUDE_DIR LIBCONFIGPP_LIBRARY LIBCONFIGPP_STATIC_LIBRARY) diff --git a/srsRAN_4G_mirror/cmake/modules/FindLimeSDR.cmake b/srsRAN_4G_mirror/cmake/modules/FindLimeSDR.cmake new file mode 100644 index 0000000..41c7e8c --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindLimeSDR.cmake @@ -0,0 +1,51 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +if(NOT LIMESDR_FOUND) + pkg_check_modules (LIMESDR_PKG LimeSuite) + + find_path(LIMESDR_INCLUDE_DIRS + NAMES LimeSuite.h + HINTS $ENV{LIMESUITE_DIR}/include + PATHS ${LIMESDR_PKG_INCLUDE_DIRS} + /usr/include/lime + /usr/local/include/lime + $ENV{LIMESUITE_DIR}/include/lime + ) + + find_library(LIMESDR_LIBRARIES + NAMES LimeSuite + HINTS $ENV{LIMESUITE_DIR}/lib + PATHS ${LIMESDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +if(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + set(LIMESDR_FOUND TRUE CACHE INTERNAL "libLimeSuite found") + message(STATUS "Found libLimeSuite: ${LIMESDR_INCLUDE_DIRS}, ${LIMESDR_LIBRARIES}") +else(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + set(LIMESDR_FOUND FALSE CACHE INTERNAL "libLimeSuite found") + message(STATUS "libLimeSuite not found.") +endif(LIMESDR_INCLUDE_DIRS AND LIMESDR_LIBRARIES) + +mark_as_advanced(LIMESDR_LIBRARIES LIMESDR_INCLUDE_DIRS) + +endif(NOT LIMESDR_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindMKL.cmake b/srsRAN_4G_mirror/cmake/modules/FindMKL.cmake new file mode 100644 index 0000000..22de689 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindMKL.cmake @@ -0,0 +1,73 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find mkl - the Intel Math Kernel Library +# Once done this will define +# MKL_FOUND - System has mkl +# MKL_INCLUDE_DIRS - The mkl include directories +# MKL_LIBRARIES - The libraries needed to use mkl +# MKL_DEFINITIONS - Compiler switches required for using mkl + +find_path(MKL_INCLUDE_DIR + NAMES mkl.h + HINTS $ENV{MKL_DIR}/include + PATHS) + +find_path(MKL_FFTW_INCLUDE_DIR + NAMES fftw3.h + HINTS $ENV{MKL_DIR}/include/fftw + PATHS) + +find_library(MKL_LIBRARIES + NAMES mkl_rt + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +find_library(MKL_CORE + NAMES libmkl_core.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +find_library(MKL_ILP + NAMES libmkl_intel_ilp64.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +find_library(MKL_SEQ + NAMES libmkl_sequential.a + HINTS $ENV{MKL_DIR}/lib/intel64 + PATHS) + +set(MKL_STATIC_LIBRARIES -Wl,--start-group ${MKL_CORE} ${MKL_ILP} ${MKL_SEQ} -Wl,--end-group -lpthread -lm -ldl) +set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR} ${MKL_FFTW_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(mkl DEFAULT_MSG + MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ MKL_INCLUDE_DIRS) + +if(MKL_FOUND) + MESSAGE(STATUS "Found MKL_INCLUDE_DIRS: ${MKL_INCLUDE_DIRS}" ) + MESSAGE(STATUS "Found MKL_LIBRARIES: ${MKL_LIBRARIES}" ) + MESSAGE(STATUS "Found MKL_STATIC_LIBRARIES: ${MKL_STATIC_LIBRARIES}" ) +endif(MKL_FOUND) + +mark_as_advanced(MKL_INCLUDE_DIR MKL_FFTW_INCLUDE_DIR MKL_LIBRARIES MKL_CORE MKL_ILP MKL_SEQ) diff --git a/srsRAN_4G_mirror/cmake/modules/FindMbedTLS.cmake b/srsRAN_4G_mirror/cmake/modules/FindMbedTLS.cmake new file mode 100644 index 0000000..2cc4508 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindMbedTLS.cmake @@ -0,0 +1,74 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find mbedtls +# +# Once done this will define +# MBEDTLS_FOUND - System has mbedtls +# MBEDTLS_INCLUDE_DIRS - The mbedtls include directories +# MBEDTLS_LIBRARIES - The mbedtls library + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(PC_MBEDTLS mbedtls) + +#find Mbedtls +FIND_PATH( + MBEDTLS_INCLUDE_DIRS + NAMES mbedtls/md.h + HINTS $ENV{MBEDTLS_DIR}/include + ${PC_MBEDTLS_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + MBEDTLS_LIBRARIES + NAMES mbedcrypto + HINTS $ENV{MBEDTLS_DIR}/lib + ${PC_MBEDTLS_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +FIND_LIBRARY( + MBEDTLS_STATIC_LIBRARIES + NAMES libmbedcrypto.a + HINTS $ENV{MBEDTLS_DIR}/lib + ${PC_MBEDTLS_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "MBEDTLS LIBRARIES: " ${MBEDTLS_LIBRARIES}) +message(STATUS "MBEDTLS STATIC LIBRARIES: " ${MBEDTLS_STATIC_LIBRARIES}) +message(STATUS "MBEDTLS INCLUDE DIRS: " ${MBEDTLS_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MbedTLS DEFAULT_MSG MBEDTLS_LIBRARIES MBEDTLS_INCLUDE_DIRS) +MARK_AS_ADVANCED(MBEDTLS_LIBRARIES MBEDTLS_STATIC_LIBRARIES MBEDTLS_INCLUDE_DIRS) diff --git a/srsRAN_4G_mirror/cmake/modules/FindPCSCLite.cmake b/srsRAN_4G_mirror/cmake/modules/FindPCSCLite.cmake new file mode 100644 index 0000000..7305baa --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindPCSCLite.cmake @@ -0,0 +1,68 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Find PCSC-Lite +# Find the native PCSC-Lite includes and library +# +# PCSCLITE_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc. +# PCSCLITE_LIBRARIES - List of libraries when using PCSC-Lite. +# PCSCLITE_FOUND - True if PCSC-Lite found. + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(PC_PCSCLITE libpcsclite) + +IF(NOT PCSCLITE_FOUND) + +FIND_PATH(PCSCLITE_INCLUDE_DIR + NAMES winscard.h + HINTS /usr/include/PCSC + /usr/local/include/PCSC + ${PC_PCSCLITE_INCLUDEDIR} + ${PC_PCSCLITE_INCLUDE_DIRS} + ${PC_PCSCLITE_INCLUDE_DIRS}/PCSC + ${CMAKE_INSTALL_PREFIX}/include +) +FIND_LIBRARY(PCSCLITE_LIBRARY NAMES pcsclite libpcsclite PCSC + HINTS ${PC_PCSCLITE_LIBDIR} + ${PC_PCSCLITE_LIBRARY_DIRS} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +# handle the QUIETLY and REQUIRED arguments and set PCSCLITE_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSCLite DEFAULT_MSG PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR) + +IF(PCSCLITE_FOUND) + SET(PCSCLITE_LIBRARIES ${PCSCLITE_LIBRARY}) +ELSE(PCSCLITE_FOUND) + SET(PCSCLITE_LIBRARIES ) +ENDIF(PCSCLITE_FOUND) + +message(STATUS "PCSC LIBRARIES: " ${PCSCLITE_LIBRARY}) +message(STATUS "PCSC INCLUDE DIRS: " ${PCSCLITE_INCLUDE_DIR}) + +MARK_AS_ADVANCED( PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR ) +ENDIF(NOT PCSCLITE_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindPolarssl.cmake b/srsRAN_4G_mirror/cmake/modules/FindPolarssl.cmake new file mode 100644 index 0000000..e305cac --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindPolarssl.cmake @@ -0,0 +1,73 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find polarssl +# +# Once done this will define +# POLARSSL_FOUND - System has polarssl +# POLARSSL_INCLUDE_DIRS - The polarssl include directories +# POLARSSL_LIBRARIES - The polarssl library + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(PC_POLARSSL polarssl) + +FIND_PATH( + POLARSSL_INCLUDE_DIRS + NAMES polarssl/version.h + HINTS $ENV{POLARSSL_DIR}/include + ${PC_POLARSSL_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + POLARSSL_LIBRARIES + NAMES polarssl + HINTS $ENV{POLARSSL_DIR}/lib + ${PC_POLARSSL_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +FIND_LIBRARY( + POLARSSL_STATIC_LIBRARIES + NAMES libpolarssl.a + HINTS $ENV{POLARSSL_DIR}/lib + ${PC_POLARSSL_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "POLARSSL LIBRARIES: " ${POLARSSL_LIBRARIES}) +message(STATUS "POLARSSL STATIC LIBRARIES: " ${POLARSSL_STATIC_LIBRARIES}) +message(STATUS "POLARSSL INCLUDE DIRS: " ${POLARSSL_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Polarssl DEFAULT_MSG POLARSSL_LIBRARIES POLARSSL_INCLUDE_DIRS) +MARK_AS_ADVANCED(POLARSSL_STATIC_LIBRARIES POLARSSL_LIBRARIES POLARSSL_INCLUDE_DIRS) diff --git a/srsRAN_4G_mirror/cmake/modules/FindRapidJSON.cmake b/srsRAN_4G_mirror/cmake/modules/FindRapidJSON.cmake new file mode 100644 index 0000000..1b2fd69 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindRapidJSON.cmake @@ -0,0 +1,97 @@ +# Copyright (c) 2011 Milo Yip (miloyip@gmail.com) +# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com) +# Distributed under the MIT License (see license.txt file) + +# ----------------------------------------------------------------------------------- +# +# Finds the rapidjson library +# +# ----------------------------------------------------------------------------------- +# +# Variables used by this module, they can change the default behaviour. +# Those variables need to be either set before calling find_package +# or exported as environment variables before running CMake: +# +# RAPIDJSON_INCLUDEDIR - Set custom include path, useful when rapidjson headers are +# outside system paths +# RAPIDJSON_USE_SSE2 - Configure rapidjson to take advantage of SSE2 capabilities +# RAPIDJSON_USE_SSE42 - Configure rapidjson to take advantage of SSE4.2 capabilities +# +# ----------------------------------------------------------------------------------- +# +# Variables defined by this module: +# +# RAPIDJSON_FOUND - True if rapidjson was found +# RAPIDJSON_INCLUDE_DIRS - Path to rapidjson include directory +# RAPIDJSON_CXX_FLAGS - Extra C++ flags required for compilation with rapidjson +# +# ----------------------------------------------------------------------------------- +# +# Example usage: +# +# set(RAPIDJSON_USE_SSE2 ON) +# set(RAPIDJSON_INCLUDEDIR "/opt/github.com/rjeczalik/rapidjson/include") +# +# find_package(rapidjson REQUIRED) +# +# include_directories("${RAPIDJSON_INCLUDE_DIRS}") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RAPIDJSON_CXX_FLAGS}") +# add_executable(foo foo.cc) +# +# ----------------------------------------------------------------------------------- + +foreach(opt RAPIDJSON_INCLUDEDIR RAPIDJSON_USE_SSE2 RAPIDJSON_USE_SSE42) + if(${opt} AND DEFINED ENV{${opt}} AND NOT ${opt} STREQUAL "$ENV{${opt}}") + message(WARNING "Conflicting ${opt} values: ignoring environment variable and using CMake cache entry.") + elseif(DEFINED ENV{${opt}} AND NOT ${opt}) + set(${opt} "$ENV{${opt}}") + endif() +endforeach() + +find_path( + RAPIDJSON_INCLUDE_DIRS + NAMES rapidjson/rapidjson.h + PATHS ${RAPIDJSON_INCLUDEDIR} + DOC "Include directory for the rapidjson library." +) + +mark_as_advanced(RAPIDJSON_INCLUDE_DIRS) + +if(RAPIDJSON_INCLUDE_DIRS) + set(RAPIDJSON_FOUND TRUE) +endif() + +mark_as_advanced(RAPIDJSON_FOUND) + +if(RAPIDJSON_USE_SSE42) + set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE42") + if(MSVC) + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE4.2") + else() + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse4.2") + endif() +else() + if(RAPIDJSON_USE_SSE2) + set(RAPIDJSON_CXX_FLAGS "-DRAPIDJSON_SSE2") + if(MSVC) + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} /arch:SSE2") + else() + set(RAPIDJSON_CXX_FLAGS "${RAPIDJSON_CXX_FLAGS} -msse2") + endif() + endif() +endif() + +mark_as_advanced(RAPIDJSON_CXX_FLAGS) + +if(RAPIDJSON_FOUND) + if(NOT rapidjson_FIND_QUIETLY) + message(STATUS "Found rapidjson header files in ${RAPIDJSON_INCLUDE_DIRS}") + if(DEFINED RAPIDJSON_CXX_FLAGS) + message(STATUS "Found rapidjson C++ extra compilation flags: ${RAPIDJSON_CXX_FLAGS}") + endif() + endif() +elseif(RapidJSON_FIND_REQUIRED) + message(FATAL_ERROR "Could not find rapidjson") +else() + message(STATUS "Optional package rapidjson was not found") +endif() diff --git a/srsRAN_4G_mirror/cmake/modules/FindSCTP.cmake b/srsRAN_4G_mirror/cmake/modules/FindSCTP.cmake new file mode 100644 index 0000000..37ef92a --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindSCTP.cmake @@ -0,0 +1,59 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find sctp +# +# Once done this will define +# SCTP_FOUND - System has mbedtls +# SCTP_INCLUDE_DIRS - The mbedtls include directories +# SCTP_LIBRARIES - The mbedtls library + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(PC_SCTP sctp) + +#find Mbedtls +FIND_PATH( + SCTP_INCLUDE_DIRS + NAMES netinet/sctp.h + HINTS ${PC_SCTP_INCLUDEDIR} + ${CMAKE_INSTALL_PREFIX}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + SCTP_LIBRARIES + NAMES sctp + HINTS ${PC_SCTP_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu/ +) + +message(STATUS "SCTP LIBRARIES: " ${SCTP_LIBRARIES}) +message(STATUS "SCTP INCLUDE DIRS: " ${SCTP_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SCTP DEFAULT_MSG SCTP_LIBRARIES SCTP_INCLUDE_DIRS) +MARK_AS_ADVANCED(SCTP_LIBRARIES SCTP_INCLUDE_DIRS) diff --git a/srsRAN_4G_mirror/cmake/modules/FindSKIQ.cmake b/srsRAN_4G_mirror/cmake/modules/FindSKIQ.cmake new file mode 100644 index 0000000..9835842 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindSKIQ.cmake @@ -0,0 +1,78 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +INCLUDE(FindPkgConfig) +#PKG_CHECK_MODULES(SKIQ SKIQ) +IF(NOT SKIQ_FOUND) + +FIND_PATH( + SKIQ_INCLUDE_DIRS + NAMES sidekiq_api.h + HINTS $ENV{SKIQ_DIR}/inc + $ENV{SKIQ_DIR}/sidekiq_core/inc + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + SKIQ_LIBRARY + NAMES sidekiq__x86_64.gcc + HINTS $ENV{SKIQ_DIR}/lib + PATHS /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/local/lib64 + /usr/local/lib32 +) + +FIND_LIBRARY( + SKIQ_LIBRARY_GLIB + NAMES libglib-2.0.a + HINTS $ENV{SKIQ_DIR}/lib/support/x86_64.gcc/usr/lib/epiq + PATHS /usr/local/lib + /usr/lib + /usr/lib/epiq + /usr/lib/x86_64-linux-gnu + /usr/local/lib64 + /usr/local/lib32 +) + +FIND_LIBRARY( + SKIQ_LIBRARY_USB + NAMES libusb-1.0.a + HINTS $ENV{SKIQ_DIR}/lib/support/x86_64.gcc/usr/lib/epiq + PATHS /usr/local/lib + /usr/lib + /usr/lib/epiq + /usr/lib/x86_64-linux-gnu + /usr/local/lib64 + /usr/local/lib32 +) + +set(SKIQ_LIBRARIES ${SKIQ_LIBRARY} ${SKIQ_LIBRARY_GLIB} ${SKIQ_LIBRARY_USB}) + +message(STATUS "SKIQ LIBRARIES " ${SKIQ_LIBRARIES}) +message(STATUS "SKIQ INCLUDE DIRS " ${SKIQ_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SKIQ DEFAULT_MSG SKIQ_LIBRARIES SKIQ_INCLUDE_DIRS) +MARK_AS_ADVANCED(SKIQ_LIBRARIES SKIQ_INCLUDE_DIRS) + +ENDIF(NOT SKIQ_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindSRSGUI.cmake b/srsRAN_4G_mirror/cmake/modules/FindSRSGUI.cmake new file mode 100644 index 0000000..e576aa4 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindSRSGUI.cmake @@ -0,0 +1,62 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# - Try to find SRSGUI +# Once done this will define +# SRSGUI_FOUND - System has srsgui +# SRSGUI_INCLUDE_DIRS - The srsgui include directories +# SRSGUI_LIBRARIES - The srsgui library + +find_package(PkgConfig) +pkg_check_modules(PC_SRSGUI QUIET srsgui) +IF(NOT SRSGUI_FOUND) + +FIND_PATH( + SRSGUI_INCLUDE_DIRS + NAMES srsgui/srsgui.h + HINTS ${PC_SRSGUI_INCLUDEDIR} + ${PC_SRSGUI_INCLUDE_DIRS} + $ENV{SRSGUI_DIR}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + SRSGUI_LIBRARIES + NAMES srsgui + HINTS ${PC_SRSGUI_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + $ENV{SRSGUI_DIR}/lib + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +message(STATUS "SRSGUI LIBRARIES " ${SRSGUI_LIBRARIES}) +message(STATUS "SRSGUI INCLUDE DIRS " ${SRSGUI_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SRSGUI DEFAULT_MSG SRSGUI_LIBRARIES SRSGUI_INCLUDE_DIRS) +MARK_AS_ADVANCED(SRSGUI_LIBRARIES SRSGUI_INCLUDE_DIRS) + +ENDIF(NOT SRSGUI_FOUND) + diff --git a/srsRAN_4G_mirror/cmake/modules/FindSSE.cmake b/srsRAN_4G_mirror/cmake/modules/FindSSE.cmake new file mode 100644 index 0000000..6596d37 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindSSE.cmake @@ -0,0 +1,210 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +#if (NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|^i[3,9]86$") +# return() +#endif() + +include(CheckCSourceRuns) + +option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON) +option(ENABLE_AVX "Enable compile-time AVX support." ON) +option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON) +option(ENABLE_FMA "Enable compile-time FMA support." ON) +option(ENABLE_AVX512 "Enable compile-time AVX512 support." ON) + +if (ENABLE_SSE) + # + # Check compiler for SSE4_1 intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + set(CMAKE_REQUIRED_FLAGS "-msse4.1") + check_c_source_runs(" + #include + #include + + int main() + { + __m128i a = _mm_setzero_si128(); + __m128i b = _mm_minpos_epu16(a); + return 0; + }" + HAVE_SSE) + endif() + + if (HAVE_SSE) + message(STATUS "SSE4.1 is enabled - target CPU must support it") + endif() + + if (ENABLE_AVX) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + set(CMAKE_REQUIRED_FLAGS "-mavx") + check_c_source_runs(" + #include + int main() + { + __m256 a, b, c; + const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; + float dst[8]; + a = _mm256_loadu_ps( src ); + b = _mm256_loadu_ps( src ); + c = _mm256_add_ps( a, b ); + _mm256_storeu_ps( dst, c ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_AVX) + endif() + + if (HAVE_AVX) + message(STATUS "AVX is enabled - target CPU must support it") + endif() + endif() + + if (ENABLE_AVX2) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + set(CMAKE_REQUIRED_FLAGS "-mavx2") + check_c_source_runs(" + #include + int main() + { + __m256i a, b, c; + const int src[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + int dst[8]; + a = _mm256_loadu_si256( (__m256i*)src ); + b = _mm256_loadu_si256( (__m256i*)src ); + c = _mm256_add_epi32( a, b ); + _mm256_storeu_si256( (__m256i*)dst, c ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_AVX2) + endif() + + if (HAVE_AVX2) + message(STATUS "AVX2 is enabled - target CPU must support it") + endif() + endif() + + if (ENABLE_FMA) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + set(CMAKE_REQUIRED_FLAGS "-mfma") + check_c_source_runs(" + #include + int main() + { + __m256 a, b, c, r; + const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f }; + float dst[8]; + a = _mm256_loadu_ps( src ); + b = _mm256_loadu_ps( src ); + c = _mm256_loadu_ps( src ); + r = _mm256_fmadd_ps( a, b, c ); + _mm256_storeu_ps( dst, r ); + int i = 0; + for( i = 0; i < 8; i++ ){ + if( ( src[i] * src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_FMA) + endif() + + if (HAVE_FMA) + message(STATUS "FMA is enabled - target CPU must support it") + endif() + endif() + + if (ENABLE_AVX512) + + # + # Check compiler for AVX intrinsics + # + if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + set(CMAKE_REQUIRED_FLAGS "-mavx512f -mavx512cd -mavx512bw -mavx512dq -DLV_HAVE_AVX512") + check_c_source_runs(" + #include + int main() + { + __m512i a, b, c; + const int src[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 , 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}; + int dst[16]; + a = _mm512_loadu_si512( (__m512i*)src ); + b = _mm512_loadu_si512( (__m512i*)src ); + c = _mm512_add_epi32( a, b ); + _mm512_storeu_si512( (__m512i*)dst, c ); + int i = 0; + for( i = 0; i < 16; i++ ){ + if( ( src[i] + src[i] ) != dst[i] ){ + return -1; + } + } + return 0; + }" + HAVE_AVX512) + endif() + + if (HAVE_AVX512) + message(STATUS "AVX512 is enabled - target CPU must support it") + endif() + elseif (${GCC_ARCH} MATCHES "native" AND CMAKE_CXX_COMPILER_ID MATCHES "GNU") + # When GCC flag -march=native and the CPU supports AVX512 (skylake-avx512 architecture), GCC uses AVX512 instructions + # automatically, independently of the rest of flags. + + # Get the CPU architecture + execute_process(COMMAND ${CMAKE_C_COMPILER} -march=native -Q --help=target + OUTPUT_VARIABLE DETECT_SKYLAKE_AVX512) + + # Check if the native architecture matches with skylake-avx512 + if (${DETECT_SKYLAKE_AVX512} MATCHES "march=.*skylake-avx512") + # Force skylake architecture without AVX512 + set(GCC_ARCH "skylake") + message(STATUS "This is a skylake-avx512 CPU, as AVX512 was disabled the architecture will be set to skylake") + endif () + endif() + + +endif() + +mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA, HAVE_AVX512) diff --git a/srsRAN_4G_mirror/cmake/modules/FindSoapySDR.cmake b/srsRAN_4G_mirror/cmake/modules/FindSoapySDR.cmake new file mode 100644 index 0000000..2bc965f --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindSoapySDR.cmake @@ -0,0 +1,54 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +message(STATUS "FINDING SOAPY.") +if(NOT SOAPYSDR_FOUND) + pkg_check_modules (SOAPYSDR_PKG SoapySDR) + + find_path(SOAPYSDR_INCLUDE_DIRS + NAMES Device.h + HINTS $ENV{SOAPY_DIR}/include + $ENV{SOAPY_DIR}/include/SoapySDR + PATHS ${SOAPYSDR_PKG_INCLUDE_DIRS} + /usr/include/SoapySDR + /usr/local/include/SoapySDR + ) + + find_library(SOAPYSDR_LIBRARIES + NAMES SoapySDR + HINTS $ENV{SOAPY_DIR}/lib + PATHS ${SOAPYSDR_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /usr/lib/arm-linux-gnueabihf + ) + + +if(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + set(SOAPYSDR_FOUND TRUE CACHE INTERNAL "libSOAPYSDR found") + message(STATUS "Found libSOAPYSDR: ${SOAPYSDR_INCLUDE_DIRS}, ${SOAPYSDR_LIBRARIES}") +else(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + set(SOAPYSDR_FOUND FALSE CACHE INTERNAL "libSOAPYSDR found") + message(STATUS "libSOAPYSDR not found.") +endif(SOAPYSDR_INCLUDE_DIRS AND SOAPYSDR_LIBRARIES) + +mark_as_advanced(SOAPYSDR_LIBRARIES SOAPYSDR_INCLUDE_DIRS) + +endif(NOT SOAPYSDR_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindUHD.cmake b/srsRAN_4G_mirror/cmake/modules/FindUHD.cmake new file mode 100644 index 0000000..47e9b4f --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindUHD.cmake @@ -0,0 +1,147 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +FIND_PACKAGE(PkgConfig REQUIRED) + +#PKG_CHECK_MODULES(UHD uhd) +IF(NOT UHD_FOUND) + +FIND_PATH( + UHD_INCLUDE_DIRS + NAMES uhd.h + HINTS $ENV{UHD_DIR}/include + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + UHD_LIBRARIES + NAMES uhd + HINTS $ENV{UHD_DIR}/lib + PATHS /usr/local/lib + /usr/lib + /usr/lib/x86_64-linux-gnu + /usr/local/lib64 + /usr/local/lib32 +) + +message(STATUS "UHD LIBRARIES " ${UHD_LIBRARIES}) +message(STATUS "UHD INCLUDE DIRS " ${UHD_INCLUDE_DIRS}) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(UHD DEFAULT_MSG UHD_LIBRARIES UHD_INCLUDE_DIRS) +MARK_AS_ADVANCED(UHD_LIBRARIES UHD_INCLUDE_DIRS) + +include(CheckCXXSourceCompiles) + +IF(UHD_FOUND) + # UHD library directory + get_filename_component(UHD_LIBRARY_DIR ${UHD_LIBRARIES} DIRECTORY) + + # Save current required variables + set(_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + set(_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) + + # Set required variables + set(CMAKE_REQUIRED_INCLUDES ${UHD_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS} -L${UHD_LIBRARY_DIR}") + set(CMAKE_REQUIRED_LIBRARIES uhd boost_program_options boost_system) + + # Checks whether the UHD driver supports X300 reset from srsRAN. This functionality requires changing the function + # `x300_make_ctrl_iface_enet` visibility in the file `uhd/host/lib/usrp/x300_fw_ctrl.cpp`. This can be accomplished + # adding the following line: + # `UHD_API wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors);` + check_cxx_source_compiles("#include + #include + #include + + uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors); + + uhd_error try_usrp_x300_reset() + { + uhd::transport::udp_simple::sptr udp_simple = uhd::transport::udp_simple::make_connected(\"\", \"49152\"); + uhd::wb_iface::sptr x300_ctrl = x300_make_ctrl_iface_enet(udp_simple, true); + x300_ctrl->poke32(0x100058, 1); + return UHD_ERROR_NONE; + } + + int main(int argc, char** argv) + { + try_usrp_x300_reset(); + return 0; + }" UHD_ENABLE_X300_FW_RESET) + + # Checks whether the UHD driver supports X300 custom RF-NOC devices + check_cxx_source_compiles("#include + #include + #include + #include + + static uhd::device3::sptr device3; + static uhd::rfnoc::ddc_block_ctrl::sptr ddc_ctrl; + static uhd::rfnoc::radio_ctrl::sptr radio_ctrl; + + uhd_error try_device3_ddc_ctrl() + { + ddc_ctrl = device3->get_block_ctrl(uhd::rfnoc::block_id_t(\"DDC_0\")); + return UHD_ERROR_NONE; + } + + uhd_error try_device3_radio_ctrl() + { + radio_ctrl = device3->get_block_ctrl(uhd::rfnoc::block_id_t(\"Radio_0\")); + return UHD_ERROR_NONE; + } + + int main(int argc, char** argv) + { + try_device3_ddc_ctrl(); + try_device3_radio_ctrl(); + return 0; + }" UHD_ENABLE_RFNOC) + + # Checks whether the UHD driver supports X300 custom RF-NOC devices + check_cxx_source_compiles("#include + #include + #include + + static uhd::device3::sptr device3; + static uhd::rfnoc::ddc_ch2_block_ctrl::sptr ddc_ctrl; + + uhd_error try_device3_ddc_ch2_ctrl() + { + ddc_ctrl = device3->get_block_ctrl(uhd::rfnoc::block_id_t(\"DDCch2_0\")); + return UHD_ERROR_NONE; + } + + int main(int argc, char** argv) + { + try_device3_ddc_ch2_ctrl(); + return 0; + }" UHD_ENABLE_CUSTOM_RFNOC) + + # Recover required variables + set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES}) + set(CMAKE_REQUIRED_INCLUDES ${_CMAKE_REQUIRED_INCLUDES}) +ENDIF(UHD_FOUND) + +ENDIF(NOT UHD_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindZeroMQ.cmake b/srsRAN_4G_mirror/cmake/modules/FindZeroMQ.cmake new file mode 100644 index 0000000..9b0abf3 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindZeroMQ.cmake @@ -0,0 +1,50 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +message(STATUS "FINDING ZEROMQ.") +if(NOT ZEROMQ_FOUND) + pkg_check_modules (ZEROMQ_PKG ZeroMQ) + + find_path(ZEROMQ_INCLUDE_DIRS + NAMES zmq.h + PATHS ${ZEROMQ_PKG_INCLUDE_DIRS} + /usr/include/zmq + /usr/local/include/zmq + ) + + find_library(ZEROMQ_LIBRARIES + NAMES zmq + PATHS ${ZEROMQ_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + /usr/lib/arm-linux-gnueabihf + ) + + if(ZEROMQ_INCLUDE_DIRS AND ZEROMQ_LIBRARIES) + set(ZEROMQ_FOUND TRUE CACHE INTERNAL "libZEROMQ found") + message(STATUS "Found libZEROMQ: ${ZEROMQ_INCLUDE_DIRS}, ${ZEROMQ_LIBRARIES}") + else(ZEROMQ_INCLUDE_DIRS AND ZEROMQ_LIBRARIES) + set(ZEROMQ_FOUND FALSE CACHE INTERNAL "libZEROMQ found") + message(STATUS "libZEROMQ not found.") + endif(ZEROMQ_INCLUDE_DIRS AND ZEROMQ_LIBRARIES) + + mark_as_advanced(ZEROMQ_LIBRARIES ZEROMQ_INCLUDE_DIRS) + +endif(NOT ZEROMQ_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/FindbladeRF.cmake b/srsRAN_4G_mirror/cmake/modules/FindbladeRF.cmake new file mode 100644 index 0000000..a6b0ab7 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/FindbladeRF.cmake @@ -0,0 +1,57 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +if(NOT BLADERF_FOUND) + pkg_check_modules (BLADERF_PKG libbladeRF) + + find_path(BLADERF_INCLUDE_DIRS + NAMES libbladeRF.h + HINTS $ENV{BLADERF_DIR}/include + PATHS ${BLADERF_PKG_INCLUDE_DIRS} + /usr/include + /usr/local/include + ) + + find_library(BLADERF_LIBRARIES + NAMES bladeRF + HINTS $ENV{BLADERF_DIR}/lib + PATHS ${BLADERF_PKG_LIBRARY_DIRS} + /usr/lib + /usr/local/lib + ) + +if(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES) + get_filename_component(bladerf_lib_dir ${BLADERF_LIBRARIES} DIRECTORY) + CHECK_LIBRARY_EXISTS(bladeRF bladerf_get_board_name ${bladerf_lib_dir} BLADERF_VERSION_OK) + if (BLADERF_VERSION_OK) + set(BLADERF_FOUND TRUE CACHE INTERNAL "libbladeRF found") + message(STATUS "Found libbladeRF: ${BLADERF_INCLUDE_DIRS}, ${BLADERF_LIBRARIES}") + else (BLADERF_VERSION_OK) + set(BLADERF_FOUND FALSE CACHE INTERNAL "libbladeRF found") + message(STATUS "libbladeRF found but not compatible. Upgrade your driver or use SoapySDR.") + endif (BLADERF_VERSION_OK) +else(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES) + set(BLADERF_FOUND FALSE CACHE INTERNAL "libbladeRF found") + message(STATUS "libbladeRF not found.") +endif(BLADERF_INCLUDE_DIRS AND BLADERF_LIBRARIES) + +mark_as_advanced(BLADERF_LIBRARIES BLADERF_INCLUDE_DIRS) + +endif(NOT BLADERF_FOUND) diff --git a/srsRAN_4G_mirror/cmake/modules/SRSRANPackage.cmake b/srsRAN_4G_mirror/cmake/modules/SRSRANPackage.cmake new file mode 100644 index 0000000..571c0e4 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/SRSRANPackage.cmake @@ -0,0 +1,83 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +SET(CPACK_PACKAGE_DESCRIPTION "srsRAN") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LTE library for SDR.") +SET(CPACK_PACKAGE_NAME "srsran") +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1), libboost-dev (>= 1.35)") + +SET(CPACK_PACKAGE_CONTACT "Ismael Gomez ") +SET(CPACK_PACKAGE_VENDOR "Software Radio Systems Limited") +SET(CPACK_PACKAGE_VERSION_MAJOR ${SRSRAN_VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${SRSRAN_VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${SRSRAN_VERSION_PATCH}) +SET(VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + +######################################################################## +# Setup additional defines for OS types +######################################################################## +IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(LINUX TRUE) +ENDIF() + +IF(LINUX AND EXISTS "/etc/debian_version") + SET(DEBIAN TRUE) +ENDIF() + +IF(LINUX AND EXISTS "/etc/redhat-release") + SET(REDHAT TRUE) +ENDIF() + +######################################################################## +# Set generator type for recognized systems +######################################################################## +IF(CPACK_GENERATOR) + #already set +ELSEIF(APPLE) + SET(CPACK_GENERATOR PackageMaker) +ELSEIF(WIN32) + SET(CPACK_GENERATOR NSIS) +ELSEIF(DEBIAN) + SET(CPACK_GENERATOR DEB) +ELSEIF(REDHAT) + SET(CPACK_GENERATOR RPM) +ELSE() + SET(CPACK_GENERATOR TGZ) +ENDIF() + +######################################################################## +# Setup CPack Debian +######################################################################## +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-dev") + +######################################################################## +# Setup CPack RPM +######################################################################## +SET(CPACK_RPM_PACKAGE_REQUIRES "boost-devel") + +######################################################################## +# Setup CPack NSIS +######################################################################## +SET(CPACK_NSIS_MODIFY_PATH ON) + + +SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}-${CMAKE_SYSTEM_PROCESSOR}") +INCLUDE(CPack) + diff --git a/srsRAN_4G_mirror/cmake/modules/SRSRANVersion.cmake b/srsRAN_4G_mirror/cmake/modules/SRSRANVersion.cmake new file mode 100644 index 0000000..cd9ace6 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/SRSRANVersion.cmake @@ -0,0 +1,25 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +SET(SRSRAN_VERSION_MAJOR 21) +SET(SRSRAN_VERSION_MINOR 10) +SET(SRSRAN_VERSION_PATCH 0) +SET(SRSRAN_VERSION_STRING "${SRSRAN_VERSION_MAJOR}.${SRSRAN_VERSION_MINOR}.${SRSRAN_VERSION_PATCH}") +SET(SRSRAN_SOVERSION 0) diff --git a/srsRAN_4G_mirror/cmake/modules/SRSRAN_install_configs.sh.in b/srsRAN_4G_mirror/cmake/modules/SRSRAN_install_configs.sh.in new file mode 100755 index 0000000..314b25f --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/SRSRAN_install_configs.sh.in @@ -0,0 +1,113 @@ +#!/bin/bash + +# Copyright 2013-2020 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +# Auto-updated by CMake with actual install path +SRSRAN_INSTALL_DIR="${CMAKE_INSTALL_PREFIX}/${DATA_DIR}" + +# check if install mode has been provided +if ([ ! $1 ]) +then + echo "Please call script with either user or service as first parameter." + echo "" + echo "E.g. ./srsran_install_configs.sh user" + echo " .. to install all config files to $HOME/.config/srsran" + echo "" + echo "E.g. ./srsran_install_configs.sh service" + echo " .. to install all config files to /etc/srsran" + exit +fi + +if [ "$1" == "user" ] +then + dest_folder="$HOME/.config/srsran" +elif [ "$1" == "service" ] +then + dest_folder="/etc/srsran" +else + echo "Please call script with either user or service as first parameter." + exit +fi + +if [ "$2" == "--force" ] +then + echo "Force overwrite called. Overwritting any existing configuration files." + read -e -p "Is this OK? [y/n]: " choice + [[ "$choice" == [Yy]* ]] && force_install="true" || exit +elif [ "$2" == "--force-no-db" ] +then + echo "Force overwrite called. Overwritting all existing configuration files, except ue_db.csv." + read -e -p "Is this OK? [y/n]: " choice + if [[ "$choice" == [Yy]* ]] ; then force_install="true" && no_db="true"; else exit; fi +elif [ "$2" == "" ] +then + : #NOOP +else + echo "Invalid command line option provided." + exit +fi + + +install_file(){ + source_path="$SRSRAN_INSTALL_DIR/$1" + dest_path=$(echo "$dest_folder/$1" | sed 's/\.[^.]*$//') # Strip .example from filename + + # Check if config file already exists in location + if [ -f $dest_path ]; then + # If --force option is selected, overwrite file + if [ "$force_install" != "true" ] && [ "$no_db" != "true" ] ; then + echo " - $dest_path already exists. Skipping it." + return + fi + # If --force-no-db option is selected, overwrite file unless it ends in ".csv" + if [ "$force_install" == "true" ] && [ "$no_db" == "true" ] && [[ $dest_path =~ \.csv$ ]]; then + echo " - $dest_path already exists. Skipping it." + return + fi + fi + + # Check if config file exists in source location + if [ -f $source_path ]; then + echo " - Installing $1 in $dest_path" + cp $source_path $dest_path + + # Set file ownership to user calling sudo + if [ $SUDO_USER ]; then + user=$SUDO_USER + chown $user:$user $dest_path + fi + else + echo " - $source_path doesn't exists. Skipping it." + fi + + return +} + +# Install all srsRAN config files +echo "Installing srsRAN configuration files:" + +# Make sure the target directory exists +if [ ! -d "$dest_folder" ]; then + echo " - Creating srsRAN config folder $dest_folder" + mkdir -p $dest_folder + if [ $? -ne 0 ]; then + exit + fi +fi + + +install_file "ue.conf.example" +install_file "enb.conf.example" +install_file "sib.conf.example" +install_file "rr.conf.example" +install_file "rb.conf.example" +install_file "epc.conf.example" +install_file "mbms.conf.example" +install_file "user_db.csv.example" + +echo "Done." diff --git a/srsRAN_4G_mirror/cmake/modules/SRSRANbuildinfo.cmake.in b/srsRAN_4G_mirror/cmake/modules/SRSRANbuildinfo.cmake.in new file mode 100644 index 0000000..8cbea73 --- /dev/null +++ b/srsRAN_4G_mirror/cmake/modules/SRSRANbuildinfo.cmake.in @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.6) + +execute_process( +COMMAND git rev-parse --abbrev-ref HEAD +WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_BRANCH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( +COMMAND git log -1 --format=%h +WORKING_DIRECTORY "@PROJECT_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_COMMIT_HASH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +message(STATUS "Generating build_info.h") +configure_file( + @PROJECT_SOURCE_DIR@/lib/include/srsran/build_info.h.in + @CMAKE_BINARY_DIR@/lib/include/srsran/build_info.h +) diff --git a/srsRAN_4G_mirror/cmake_uninstall.cmake.in b/srsRAN_4G_mirror/cmake_uninstall.cmake.in new file mode 100644 index 0000000..c869827 --- /dev/null +++ b/srsRAN_4G_mirror/cmake_uninstall.cmake.in @@ -0,0 +1,26 @@ +if(POLICY CMP0007) + cmake_policy(SET CMP0007 OLD) +endif(POLICY CMP0007) + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif (NOT ${rm_retval} EQUAL 0) + else (EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif (EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) diff --git a/srsRAN_4G_mirror/debian/changelog b/srsRAN_4G_mirror/debian/changelog new file mode 100644 index 0000000..d5bf44d --- /dev/null +++ b/srsRAN_4G_mirror/debian/changelog @@ -0,0 +1,77 @@ +srslte (19.06-0ubuntu1~srslte1~19.04) disco; urgency=medium + + * Update to srsLTE 19.06 (Ubuntu Disco) + + -- Pedro Alvarez Fri, 30 August 2019 11:00:03 +0000 + +srslte (19.06-0ubuntu1~srslte1~18.10) cosmic; urgency=medium + + * Update to srsLTE 19.06 (Ubuntu Cosmic) + + -- Pedro Alvarez Fri, 30 August 2019 10:40:03 +0000 + +srslte (19.06-0ubuntu1~srslte1~18.04) bionic; urgency=medium + + * Update to srsLTE 19.06 (Ubuntu Bionic) + + -- Pedro Alvarez Fri, 30 August 2019 09:53:03 +0000 + +srslte (19.06-0ubuntu1~srslte1~16.04) xenial; urgency=medium + + * Update to srsLTE 19.06 (Ubuntu Xenial) + + -- Pedro Alvarez Thu, 29 August 2019 15:00:03 +0000 + +srslte (19.03-0ubuntu1~srslte1~16.04) xenial; urgency=medium + + * Update to srsLTE 19.03 (Ubuntu Xenial) + + -- Pedro Alvarez Tue, 14 May 2019 17:27:03 +0000 + +srslte (19.03-0ubuntu1~srslte1~19.04) disco; urgency=medium + + * Update to srsLTE 19.03 (Ubuntu Disco) + + -- Pedro Alvarez Tue, 14 May 2019 17:27:03 +0000 + +srslte (19.03-0ubuntu1~srslte1~18.10) cosmic; urgency=medium + + * Update to srsLTE 19.03 (Ubuntu Cosmic) + + -- Pedro Alvarez Tue, 14 May 2019 17:27:03 +0000 + +srslte (19.03-0ubuntu1~srslte1~18.04) bionic; urgency=medium + + * Update to srsLTE 19.03 (Ubuntu Bionic) + + -- Pedro Alvarez Tue, 14 May 2019 17:27:03 +0000 + +srslte (18.12-0ubuntu1) bionic; urgency=medium + + * Update to srsLTE 18.12 + + -- Andre Puschmann Mon, 21 Jan 2019 13:50:00 +0200 + +srslte (18.09-0ubuntu1) bionic; urgency=medium + + * Update to srsLTE 18.09 + + -- Andre Puschmann Wed, 15 Oct 2018 10:05:00 +0200 + +srslte (18.06.1-0ubuntu1) bionic; urgency=medium + + * Update to srsLTE 18.06.1 + + -- Andre Puschmann Wed, 18 Jul 2018 11:34:00 +0200 + +srslte (18.05~SNAPSHOT-0ubuntu2) bionic; urgency=medium + + * Update pkg deps + + -- Andre Puschmann Tue, 01 Jun 2018 15:10:00 +0200 + +srslte (18.05~SNAPSHOT-0ubuntu1) bionic; urgency=medium + + * Initial release of deb's + + -- Andre Puschmann Tue, 01 Jun 2018 14:10:00 +0200 diff --git a/srsRAN_4G_mirror/debian/compat b/srsRAN_4G_mirror/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/srsRAN_4G_mirror/debian/compat @@ -0,0 +1 @@ +9 diff --git a/srsRAN_4G_mirror/debian/control b/srsRAN_4G_mirror/debian/control new file mode 100644 index 0000000..3126b51 --- /dev/null +++ b/srsRAN_4G_mirror/debian/control @@ -0,0 +1,103 @@ +Source: srsran +Section: universe/misc +Priority: optional +Maintainer: srsRAN Packagers +Build-Depends: + debhelper (>= 9), + dh-exec, + cmake, + build-essential, + libfftw3-dev, + libmbedtls-dev, + libboost-program-options-dev, + libconfig++-dev, + libsctp-dev, + libuhd-dev, + uhd-host, + txt2man +Standards-Version: 4.2.1 +Homepage: http://www.softwareradiosystems.com +Vcs-Git: https://github.com/srsRAN/srsRAN.git +Vcs-Browser: https://github.com/srsRAN/srsRAN/ + +Package: srsran-dev +Architecture: any +Multi-Arch: same +Section: libdevel +Depends: ${shlibs:Depends}, + ${misc:Depends}, + srsran-core:any (= ${binary:Version}) +Breaks: srslte (<= 19.03-0ubuntu1) +Replaces: srslte (<= 19.03-0ubuntu1) +Description: Static libraries and headers for srsran + This software allows you to run a full end-to-end, open-source 4G/5G system. + It contains a UE, eNB and EPC implementation. + . + This package contains the development files - static libraries and headers + +Package: srsran +Architecture: all +Depends: ${shlibs:Depends}, + ${misc:Depends}, + srsenb (>= ${source:Version}), srsenb (<< ${source:Upstream-Version}.0~), + srsue (>= ${source:Version}), srsue (<< ${source:Upstream-Version}.0~), + srsepc (>= ${source:Version}), srsepc (<< ${source:Upstream-Version}.0~) +Description: LTE software suite for software defined radios (metapackage) + This software allows you to run a full end-to-end, open-source LTE system. + It contains a UE, eNB and EPC implementation. + . + This package installs all srsRAN components. + +Package: srsenb +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + srsran-core (= ${binary:Version}) +Breaks: srslte (<= 19.03-0ubuntu1) +Replaces: srslte (<= 19.03-0ubuntu1) +Description: Complete SDR LTE eNodeB application + This software allows you to run a full end-to-end, open-source LTE system. + It contains a UE, eNB and EPC implementation. + . + This package contains srsENB only. For running a full network, a core network + component, such as srsEPC, is needed. + +Package: srsepc +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + srsran-core (= ${binary:Version}) +Recommends: srsenb +Breaks: srsepc (<= 19.03-0ubuntu1) +Replaces: srsepc (<= 19.03-0ubuntu1) +Description: Light-weight LTE core network implementation + This software allows you to run a full end-to-end, open-source LTE system. + It contains a UE, eNB and EPC implementation. + . + This package contains a light-weight LTE core network implementation with MME, HSS and S/P-GW. + +Package: srsran-core +Architecture: any +Multi-Arch: allowed +Depends: ${shlibs:Depends}, + ${misc:Depends} +Breaks: srslte-core (<= 19.03-0ubuntu1) +Replaces: srslte-core (<= 19.03-0ubuntu1) +Description: Common files for srsRAN + This software allows you to run a full end-to-end, open-source 4G/5G system. + It contains a UE, eNB and EPC implementation. + . + This package contains the common files for srsenb, srsue and srsepc. + +Package: srsue +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + srsran-core (= ${binary:Version}) +Breaks: srsue (<= 19.03-0ubuntu1) +Replaces: srsue (<= 19.03-0ubuntu1) +Description: User Equipment implementation for LTE + This software enables using a software defined radio as the user equipment + connecting to an LTE network. + . + srsUE provides a complete SDR LTE UE application featuring all layers from PHY to IP. \ No newline at end of file diff --git a/srsRAN_4G_mirror/debian/copyright b/srsRAN_4G_mirror/debian/copyright new file mode 100644 index 0000000..7295978 --- /dev/null +++ b/srsRAN_4G_mirror/debian/copyright @@ -0,0 +1,149 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: srsRAN +Upstream-Contact: srsRAN packaging team +License: AGPL-3+ +Copyright: 2013-2021, Software Radio Systems Limited. +Source: https://www.github.com/srsRAN + +Files: * +Copyright: 2013-2021, Software Radio Systems Limited. +License: AGPL-3+ + + +The following files are used within srsRAN: + +Files: lib/src/phy/fec/viterbi37_port.c + lib/src/phy/fec/viterbi37_sse.c + lib/src/phy/fec/viterbi37_avx2.c + lib/src/phy/fec/viterbi37_neon.c + lib/src/phy/fec/viterbi37_avx2_16bit.c + lib/src/phy/fec/parity.c +Copyright: 2009, Phil Karn, KA9Q +License: LGPL-2.1 + +Files: srsue/src/upper/pcsc_usim.cc + srsue/hdr/upper/pcsc_usim.h +Copyright: 2002-2014, Jouni Malinen +License: BSD-3-clause + +Files: lib/include/srsran/asn1/liblte_common.h + lib/include/srsran/asn1/liblte_mme.h + lib/include/srsran/common/liblte_security.h + lib/src/asn1/liblte_common.cc + lib/src/asn1/liblte_mme.cc + lib/src/common/liblte_security.cc +Copyright: 2012-2014 Ben Wojtowicz +License: AGPL-3+ + +Files: lib/include/srsran/srslog/bundled/fmt/chrono.h + lib/include/srsran/srslog/bundled/fmt/color.h + lib/include/srsran/srslog/bundled/fmt/compile.h + lib/include/srsran/srslog/bundled/fmt/core.h + lib/include/srsran/srslog/bundled/fmt/format.h + lib/include/srsran/srslog/bundled/fmt/format-inl.h + lib/include/srsran/srslog/bundled/fmt/LICENSE.rst + lib/include/srsran/srslog/bundled/fmt/locale.h + lib/include/srsran/srslog/bundled/fmt/os.h + lib/include/srsran/srslog/bundled/fmt/ostream.h + lib/include/srsran/srslog/bundled/fmt/posix.h + lib/include/srsran/srslog/bundled/fmt/printf.h + lib/include/srsran/srslog/bundled/fmt/ranges.h + lib/src/srsran/bundled/fmt/format.cc + lib/src/srsran/bundled/fmt/os.cc +Copyright: 2012-2020, Victor Zverovich +License: MIT + +Files: lib/include/srsran/common/backward.hpp + cmake/modules/FindBackward.cmake +Copyright: 2013, Google Inc. +License: MIT + +Files: cmake/modules/CheckAtomic.cmake +Copyright: 2015, Charles J. Cliffe +License: MIT + +License: AGPL-3+ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + . + This program 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 Affero General Public License for more details. + . + On Debian systems, the complete text of the AGPL 3 can be found in + /usr/share/doc/srsran/LICENSE + + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + . + This library 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 + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +License: BSD-3-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +License: MIT +Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, +portions of this Software are embedded into a machine-executable object +form of such source code, you may redistribute such embedded portions in +such object form without including the above copyright and permission notices. diff --git a/srsRAN_4G_mirror/debian/man/genmanpages.sh b/srsRAN_4G_mirror/debian/man/genmanpages.sh new file mode 100755 index 0000000..5b60de6 --- /dev/null +++ b/srsRAN_4G_mirror/debian/man/genmanpages.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +txt2man -d "${CHANGELOG_DATE}" -t SRSENB -s 8 srsenb.txt > srsenb.8 +txt2man -d "${CHANGELOG_DATE}" -t SRSEPC -s 8 srsepc.txt > srsepc.8 +txt2man -d "${CHANGELOG_DATE}" -t SRSUE -s 8 srsue.txt > srsue.8 diff --git a/srsRAN_4G_mirror/debian/man/srsenb.txt b/srsRAN_4G_mirror/debian/man/srsenb.txt new file mode 100644 index 0000000..42501eb --- /dev/null +++ b/srsRAN_4G_mirror/debian/man/srsenb.txt @@ -0,0 +1,26 @@ +NAME + srsENB - A complete SDR LTE eNodeB application + +SYNOPSIS + srsenb [options] + +DESCRIPTION + + srsENB provides the Evolved Node B (eNodeB or eNB) part in the LTE network. + + Features: + + - Round Robin MAC scheduler with FAPI-like C++ API + - SR support + - Periodic and Aperiodic CQI feedback support + - Standard S1AP and GTP-U interfaces to the Core Network + - 150 Mbps DL in 20 MHz MIMO TM3/TM4 with commercial UEs + - 75 Mbps DL in SISO configuration with commercial UEs + - 50 Mbps UL in 20 MHz with commercial UEs + + An example configuration file is available in /usr/share/srsran/enb.conf.example + +OPTIONS + + -h/--help Produce help message + -v/--version Print version information and exit diff --git a/srsRAN_4G_mirror/debian/man/srsepc.txt b/srsRAN_4G_mirror/debian/man/srsepc.txt new file mode 100644 index 0000000..68beac9 --- /dev/null +++ b/srsRAN_4G_mirror/debian/man/srsepc.txt @@ -0,0 +1,21 @@ +NAME + srsEPC - A light-weight LTE core network implementation with MME, HSS and S/P-GW. + +SYNOPSIS + srsepc [options] + +DESCRIPTION + + srsEPC provides a light-weight LTE core network implementation. + It constist of a single binary, and provides the following features: + + - MME (Mobility Management Entity) with standard S1AP and GTP-U interface to eNB + - S/P-GW with standard SGi exposed as virtual network interface (TUN device) + - HSS (Home Subscriber Server) with configurable user database in CSV format + + An example configuration file is available in /usr/share/srsran/epc.conf.example + +OPTIONS + + -h/--help Produce help message + -v/--version Print version information and exit diff --git a/srsRAN_4G_mirror/debian/man/srsue.txt b/srsRAN_4G_mirror/debian/man/srsue.txt new file mode 100644 index 0000000..149f9c9 --- /dev/null +++ b/srsRAN_4G_mirror/debian/man/srsue.txt @@ -0,0 +1,26 @@ +NAME + srsUE - A SDR LTE UE application featuring all layers from PHY to IP + +SYNOPSIS + srsue [options] + +DESCRIPTION + + srsUE provides a complete SDR LTE UE application featuring all layers from PHY to IP. + + Features: + + - Cell search and synchronization procedure for the UE + - Soft USIM supporting Milenage and XOR authentication + - Hard USIM support using PCSC framework + - Virtual network interface tun_srsue created upon network attach + - 150 Mbps DL in 20 MHz MIMO TM3/TM4 configuration in i7 Quad-Core CPU. + - 75 Mbps DL in 20 MHz SISO configuration in i7 Quad-Core CPU. + - 36 Mbps DL in 10 MHz SISO configuration in i5 Dual-Core CPU. + + An example configuration file is available in /usr/share/srsran/ue.conf.example + +OPTIONS + + -h/--help Produce help message + -v/--version Print version information and exit diff --git a/srsRAN_4G_mirror/debian/packager.sh b/srsRAN_4G_mirror/debian/packager.sh new file mode 100755 index 0000000..3f66ff0 --- /dev/null +++ b/srsRAN_4G_mirror/debian/packager.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +RELEASE=19.06 +DISTRO=disco +COMMIT=eda7ca69a09933526e9318bcf553af0dc0b81598 +REL_FLAG=releases + +echo 'Packaging srsRAN release' $RELEASE 'for Ubuntu' $DISTRO + +# Make build dir for the package +BUILD_DIR=~/build-area/srsran_$RELEASE/$REL_FLAG/$DISTRO +mkdir -p $BUILD_DIR + +# Make tarball of the package source +pushd ~/srsRAN +git archive $COMMIT -o $BUILD_DIR/srsran_$DISTRO.tar.gz +popd + +# Copy original tarball +cp ~/build-area/srsran_$RELEASE/$REL_FLAG/srsran_$RELEASE.orig.tar.gz $BUILD_DIR + +mkdir $BUILD_DIR/srsRAN +pushd $BUILD_DIR/srsRAN +tar -vxzf ../srsran_$DISTRO.tar.gz +popd diff --git a/srsRAN_4G_mirror/debian/rules b/srsRAN_4G_mirror/debian/rules new file mode 100755 index 0000000..3c5479a --- /dev/null +++ b/srsRAN_4G_mirror/debian/rules @@ -0,0 +1,29 @@ +#!/usr/bin/make -f +# Uncomment this to turn on verbose mode. +export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +%: + dh $@ --parallel + +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + +override_dh_auto_configure: + dh_auto_configure --buildsystem=cmake -- $(extraopts) $(CEPH_EXTRA_CMAKE_ARGS) -DCMAKE_BUILD_TYPE=RelWithDebInfo + +override_dh_auto_test: + # skip executing tests + +override_dh_installman: + cd debian/man ; CHANGELOG_DATE="$(CHANGELOG_DATE)" ./genmanpages.sh + dh_installman -a + +override_dh_auto_clean: + dh_auto_clean + $(RM) debian/man/*.1 + +override_dh_installinit: + dh_installinit --no-start diff --git a/srsRAN_4G_mirror/debian/source/format b/srsRAN_4G_mirror/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/srsRAN_4G_mirror/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/srsRAN_4G_mirror/debian/srsenb.install b/srsRAN_4G_mirror/debian/srsenb.install new file mode 100644 index 0000000..e37de24 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsenb.install @@ -0,0 +1,2 @@ +usr/bin/srsenb +debian/srsenb.service lib/systemd/system/ diff --git a/srsRAN_4G_mirror/debian/srsenb.manpages b/srsRAN_4G_mirror/debian/srsenb.manpages new file mode 100644 index 0000000..a130466 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsenb.manpages @@ -0,0 +1 @@ +debian/man/srsenb.8 diff --git a/srsRAN_4G_mirror/debian/srsenb.service b/srsRAN_4G_mirror/debian/srsenb.service new file mode 100644 index 0000000..7682d12 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsenb.service @@ -0,0 +1,11 @@ +[Unit] +Description=Software Radio System's LTE eNB implementation + +[Service] +Type=simple +Restart=always +ExecStart=/usr/bin/srsenb /etc/srsran/enb.conf +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/srsRAN_4G_mirror/debian/srsepc.install b/srsRAN_4G_mirror/debian/srsepc.install new file mode 100644 index 0000000..f61d996 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsepc.install @@ -0,0 +1,4 @@ +usr/bin/srsepc +usr/bin/srsepc_if_masq.sh +debian/srsepc.service lib/systemd/system/ +usr/bin/srsmbms diff --git a/srsRAN_4G_mirror/debian/srsepc.manpages b/srsRAN_4G_mirror/debian/srsepc.manpages new file mode 100644 index 0000000..bf7cc6b --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsepc.manpages @@ -0,0 +1 @@ +debian/man/srsepc.8 diff --git a/srsRAN_4G_mirror/debian/srsepc.service b/srsRAN_4G_mirror/debian/srsepc.service new file mode 100644 index 0000000..a332f55 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsepc.service @@ -0,0 +1,11 @@ +[Unit] +Description=Software Radio System's light-weight EPC implementation + +[Service] +Type=simple +Restart=always +ExecStart=/usr/bin/srsepc /etc/srsran/epc.conf +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/srsRAN_4G_mirror/debian/srslte-core.config b/srsRAN_4G_mirror/debian/srslte-core.config new file mode 100755 index 0000000..2ed1714 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srslte-core.config @@ -0,0 +1,13 @@ +#!/bin/sh + +# Exit on error +set -e + +# Source debconf library. +. /usr/share/debconf/confmodule + +# Ask questions +db_input low srsran/install_configs_question || true + +# Show interface +db_go || true diff --git a/srsRAN_4G_mirror/debian/srslte-core.install b/srsRAN_4G_mirror/debian/srslte-core.install new file mode 100644 index 0000000..cc51264 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srslte-core.install @@ -0,0 +1,3 @@ +usr/lib/*/libsrsran_rf.so* +usr/share/srsran +usr/bin/srsran_install_configs.sh diff --git a/srsRAN_4G_mirror/debian/srslte-core.postinst b/srsRAN_4G_mirror/debian/srslte-core.postinst new file mode 100755 index 0000000..cd09650 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srslte-core.postinst @@ -0,0 +1,14 @@ +#!/bin/bash + +# Source debconf library. +. /usr/share/debconf/confmodule + +# Fetching configuration from debconf +db_get srsran/install_configs_question +ANSWER1=$RET + +if [ $ANSWER1 == "true" ]; then + srsran_install_configs.sh user +fi + +#DEBHELPER# diff --git a/srsRAN_4G_mirror/debian/srslte-core.templates b/srsRAN_4G_mirror/debian/srslte-core.templates new file mode 100644 index 0000000..37f94f7 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srslte-core.templates @@ -0,0 +1,6 @@ +Template: srsran/install_configs_question +Type: boolean +Default: true +Description: Install configs? + This installs the default srsRAN configuration files to the user's + home directory (~/.config/srsran) but keeps any existing config files. diff --git a/srsRAN_4G_mirror/debian/srslte-dev.install b/srsRAN_4G_mirror/debian/srslte-dev.install new file mode 100644 index 0000000..6d9efca --- /dev/null +++ b/srsRAN_4G_mirror/debian/srslte-dev.install @@ -0,0 +1,2 @@ +usr/lib/*/*.a +usr/include/srsran diff --git a/srsRAN_4G_mirror/debian/srsue.install b/srsRAN_4G_mirror/debian/srsue.install new file mode 100644 index 0000000..e03e7b1 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsue.install @@ -0,0 +1,2 @@ +usr/bin/srsue +debian/srsue.service lib/systemd/system/ diff --git a/srsRAN_4G_mirror/debian/srsue.manpages b/srsRAN_4G_mirror/debian/srsue.manpages new file mode 100644 index 0000000..1732496 --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsue.manpages @@ -0,0 +1 @@ +debian/man/srsue.8 diff --git a/srsRAN_4G_mirror/debian/srsue.service b/srsRAN_4G_mirror/debian/srsue.service new file mode 100644 index 0000000..5a3e2bc --- /dev/null +++ b/srsRAN_4G_mirror/debian/srsue.service @@ -0,0 +1,11 @@ +[Unit] +Description=Software Radio Systems's LTE UE implementation + +[Service] +Type=simple +Restart=always +ExecStart=/usr/bin/srsue /etc/srsran/ue.conf +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/srsRAN_4G_mirror/lib/CMakeLists.txt b/srsRAN_4G_mirror/lib/CMakeLists.txt new file mode 100644 index 0000000..29b1f2f --- /dev/null +++ b/srsRAN_4G_mirror/lib/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(src) +add_subdirectory(include) +add_subdirectory(examples) +add_subdirectory(test) + +######################################################################## +# Install library headers +######################################################################## +INSTALL( DIRECTORY include/ + DESTINATION "${INCLUDE_DIR}" + FILES_MATCHING PATTERN "*.h" ) \ No newline at end of file diff --git a/srsRAN_4G_mirror/lib/examples/CMakeLists.txt b/srsRAN_4G_mirror/lib/examples/CMakeLists.txt new file mode 100644 index 0000000..2581ede --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/CMakeLists.txt @@ -0,0 +1,110 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +################################################################# +# Applications +################################################################# + +add_executable(synch_file synch_file.c) +target_link_libraries(synch_file srsran_phy) + +################################################################# +# These can be compiled without UHD or graphics support +################################################################# + +if(RF_FOUND) + add_executable(pdsch_ue pdsch_ue.c) + target_link_libraries(pdsch_ue srsran_phy srsran_common srsran_rf pthread) + + add_executable(pdsch_enodeb pdsch_enodeb.c) + target_link_libraries(pdsch_enodeb srsran_phy srsran_common srsran_rf pthread) + + add_executable(npdsch_enodeb npdsch_enodeb.c) + target_link_libraries(npdsch_enodeb srsran_phy srsran_rf pthread) + + add_executable(npdsch_ue npdsch_ue.c npdsch_ue_helper.cc) + target_link_libraries(npdsch_ue srsran_common srsran_phy srsran_rf pthread rrc_asn1) +else(RF_FOUND) + add_definitions(-DDISABLE_RF) + + add_executable(pdsch_ue pdsch_ue.c) + target_link_libraries(pdsch_ue srsran_common srsran_phy pthread) + + add_executable(pdsch_enodeb pdsch_enodeb.c) + target_link_libraries(pdsch_enodeb srsran_common srsran_phy pthread) + + add_executable(npdsch_enodeb npdsch_enodeb.c) + target_link_libraries(npdsch_enodeb srsran_phy pthread) + + add_executable(npdsch_ue npdsch_ue.c npdsch_ue_helper.cc) + target_link_libraries(npdsch_ue srsran_common srsran_phy pthread rrc_asn1) +endif(RF_FOUND) + +if(SRSGUI_FOUND) + include_directories(${SRSGUI_INCLUDE_DIRS}) + target_link_libraries(pdsch_ue ${SRSGUI_LIBRARIES}) + target_link_libraries(npdsch_ue ${SRSGUI_LIBRARIES}) + add_definitions(-DENABLE_GUI) +endif(SRSGUI_FOUND) + +if (ZEROMQ_FOUND) + add_executable(zmq_remote_rx zmq_remote_rx.c) + target_link_libraries(zmq_remote_rx srsran_phy srsran_rf) +endif (ZEROMQ_FOUND) + +################################################################# +# These examples need the UHD driver +################################################################# + +if(RF_FOUND) + + add_executable(cell_search cell_search.c) + target_link_libraries(cell_search srsran_phy srsran_common srsran_rf) + + add_executable(usrp_capture usrp_capture.c) + target_link_libraries(usrp_capture srsran_phy srsran_rf) + + add_executable(usrp_capture_sync usrp_capture_sync.c) + target_link_libraries(usrp_capture_sync srsran_phy srsran_rf) + + add_executable(usrp_capture_sync_nbiot usrp_capture_sync_nbiot.c) + target_link_libraries(usrp_capture_sync_nbiot srsran_rf srsran_phy) + + add_executable(cell_search_nbiot cell_search_nbiot.c) + target_link_libraries(cell_search_nbiot srsran_rf srsran_phy) + + add_executable(usrp_txrx usrp_txrx.c) + target_link_libraries(usrp_txrx srsran_phy srsran_rf) + + add_executable(pssch_ue pssch_ue.c) + target_link_libraries(pssch_ue srsran_phy srsran_common srsran_rf pthread) + + if(SRSGUI_FOUND) + target_link_libraries(pssch_ue ${SRSGUI_LIBRARIES}) + endif(SRSGUI_FOUND) + + message(STATUS " examples will be installed.") + +else(RF_FOUND) + message(STATUS " examples will NOT BE INSTALLED.") +endif(RF_FOUND) + +# Add eNB/UE IQ test +add_subdirectory(test) diff --git a/srsRAN_4G_mirror/lib/examples/cell_search.c b/srsRAN_4G_mirror/lib/examples/cell_search.c new file mode 100644 index 0000000..bcb7c3c --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/cell_search.c @@ -0,0 +1,273 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "srsran/srsran.h" + +#include "srsran/common/crash_handler.h" +#include "srsran/phy/rf/rf_utils.h" + +#ifndef DISABLE_RF +#include "srsran/phy/rf/rf.h" +#endif + +#define MHZ 1000000 +#define SAMP_FREQ 1920000 +#define FLEN 9600 +#define FLEN_PERIOD 0.005 + +#define MAX_EARFCN 1000 + +int band = -1; +int earfcn_start = -1, earfcn_end = -1; + +cell_search_cfg_t cell_detect_config = {.max_frames_pbch = SRSRAN_DEFAULT_MAX_FRAMES_PBCH, + .max_frames_pss = SRSRAN_DEFAULT_MAX_FRAMES_PSS, + .nof_valid_pss_frames = SRSRAN_DEFAULT_NOF_VALID_PSS_FRAMES, + .init_agc = 0, + .force_tdd = false}; + +struct cells { + srsran_cell_t cell; + float freq; + int dl_earfcn; + float power; +}; +struct cells results[1024]; + +float rf_gain = 70.0; +char* rf_args = ""; +char* rf_dev = ""; + +void usage(char* prog) +{ + printf("Usage: %s [agsendtvb] -b band\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-d RF devicename [Default %s]\n", rf_dev); + printf("\t-g RF gain [Default %.2f dB]\n", rf_gain); + printf("\t-s earfcn_start [Default All]\n"); + printf("\t-e earfcn_end [Default All]\n"); + printf("\t-n nof_frames_total [Default 100]\n"); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "agsendvb")) != -1) { + switch (opt) { + case 'a': + rf_args = argv[optind]; + break; + case 'b': + band = (int)strtol(argv[optind], NULL, 10); + break; + case 'd': + rf_dev = argv[optind]; + break; + case 's': + earfcn_start = (int)strtol(argv[optind], NULL, 10); + break; + case 'e': + earfcn_end = (int)strtol(argv[optind], NULL, 10); + break; + case 'n': + cell_detect_config.max_frames_pss = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (band == -1) { + usage(argv[0]); + exit(-1); + } +} + +int srsran_rf_recv_wrapper(void* h, void* data, uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ---- ", nsamples); + return srsran_rf_recv_with_time((srsran_rf_t*)h, data, nsamples, 1, NULL, NULL); +} + +bool go_exit = false; + +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } +} + +static SRSRAN_AGC_CALLBACK(srsran_rf_set_rx_gain_wrapper) +{ + srsran_rf_set_rx_gain((srsran_rf_t*)h, gain_db); +} + +int main(int argc, char** argv) +{ + int n; + srsran_rf_t rf; + srsran_ue_cellsearch_t cs; + srsran_ue_cellsearch_result_t found_cells[3]; + int nof_freqs; + srsran_earfcn_t channels[MAX_EARFCN]; + uint32_t freq; + uint32_t n_found_cells = 0; + + srsran_debug_handle_crash(argc, argv); + + parse_args(argc, argv); + + printf("Opening RF device...\n"); + + if (srsran_rf_open_devname(&rf, rf_dev, rf_args, 1)) { + ERROR("Error opening rf"); + exit(-1); + } + if (!cell_detect_config.init_agc) { + srsran_rf_set_rx_gain(&rf, rf_gain); + } else { + printf("Starting AGC thread...\n"); + if (srsran_rf_start_gain_thread(&rf, false)) { + ERROR("Error opening rf"); + exit(-1); + } + srsran_rf_set_rx_gain(&rf, 50); + } + + // Supress RF messages + srsran_rf_suppress_stdout(&rf); + + nof_freqs = srsran_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); + if (nof_freqs < 0) { + ERROR("Error getting EARFCN list"); + exit(-1); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + if (srsran_ue_cellsearch_init(&cs, cell_detect_config.max_frames_pss, srsran_rf_recv_wrapper, (void*)&rf)) { + ERROR("Error initiating UE cell detect"); + exit(-1); + } + + if (cell_detect_config.max_frames_pss) { + srsran_ue_cellsearch_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames); + } + if (cell_detect_config.init_agc) { + srsran_rf_info_t* rf_info = srsran_rf_get_info(&rf); + srsran_ue_sync_start_agc(&cs.ue_sync, + srsran_rf_set_rx_gain_wrapper, + rf_info->min_rx_gain, + rf_info->max_rx_gain, + cell_detect_config.init_agc); + } + + for (freq = 0; freq < nof_freqs && !go_exit; freq++) { + /* set rf_freq */ + srsran_rf_set_rx_freq(&rf, 0, (double)channels[freq].fd * MHZ); + INFO("Set rf_freq to %.3f MHz", (double)channels[freq].fd * MHZ / 1000000); + + printf( + "[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS.\n", freq, nof_freqs, channels[freq].id, channels[freq].fd); + fflush(stdout); + + if (SRSRAN_VERBOSE_ISINFO()) { + printf("\n"); + } + + bzero(found_cells, 3 * sizeof(srsran_ue_cellsearch_result_t)); + + INFO("Setting sampling frequency %.2f MHz for PSS search", SRSRAN_CS_SAMP_FREQ / 1000000); + srsran_rf_set_rx_srate(&rf, SRSRAN_CS_SAMP_FREQ); + INFO("Starting receiver..."); + srsran_rf_start_rx_stream(&rf, false); + + n = srsran_ue_cellsearch_scan(&cs, found_cells, NULL); + if (n < 0) { + ERROR("Error searching cell"); + exit(-1); + } else if (n > 0) { + for (int i = 0; i < 3; i++) { + if (found_cells[i].psr > 2.0) { + srsran_cell_t cell; + cell.id = found_cells[i].cell_id; + cell.cp = found_cells[i].cp; + int ret = rf_mib_decoder(&rf, 1, &cell_detect_config, &cell, NULL); + if (ret < 0) { + ERROR("Error decoding MIB"); + exit(-1); + } + if (ret == SRSRAN_UE_MIB_FOUND) { + printf("Found CELL ID %d. %d PRB, %d ports\n", cell.id, cell.nof_prb, cell.nof_ports); + if (cell.nof_ports > 0) { + results[n_found_cells].cell = cell; + results[n_found_cells].freq = channels[freq].fd; + results[n_found_cells].dl_earfcn = channels[freq].id; + results[n_found_cells].power = found_cells[i].peak; + n_found_cells++; + } + } + } + } + } + } + + printf("\n\nFound %d cells\n", n_found_cells); + for (int i = 0; i < n_found_cells; i++) { + printf("Found CELL %.1f MHz, EARFCN=%d, PHYID=%d, %d PRB, %d ports, PSS power=%.1f dBm\n", + results[i].freq, + results[i].dl_earfcn, + results[i].cell.id, + results[i].cell.nof_prb, + results[i].cell.nof_ports, + srsran_convert_power_to_dB(results[i].power)); + } + + printf("\nBye\n"); + + srsran_ue_cellsearch_free(&cs); + srsran_rf_close(&rf); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/cell_search_nbiot.c b/srsRAN_4G_mirror/lib/examples/cell_search_nbiot.c new file mode 100644 index 0000000..c7e9e39 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/cell_search_nbiot.c @@ -0,0 +1,261 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/phy/rf/rf_utils.h" +#include "srsran/phy/ue/ue_cell_search_nbiot.h" + +#ifndef DISABLE_RF +#include "srsran/phy/rf/rf.h" +#endif + +#define MHZ 1000000 +#define SAMP_FREQ 1920000 +#define FLEN 9600 +#define FLEN_PERIOD 0.005 + +#define MAX_EARFCN 1000 +#define RASTER_OFFSET 2500 + +#define NUM_RASTER_OFFSET 5 +double raster_offset[NUM_RASTER_OFFSET] = {0.0, 2500.0, -2500.0, 7500.0, -7500.0}; + +int band = -1; +int earfcn_start = -1, earfcn_end = -1; + +cell_search_cfg_t cell_detect_config = {.max_frames_pbch = SRSRAN_DEFAULT_MAX_FRAMES_NPBCH, + .max_frames_pss = SRSRAN_DEFAULT_MAX_FRAMES_NPSS, + .nof_valid_pss_frames = SRSRAN_DEFAULT_NOF_VALID_NPSS_FRAMES, + .init_agc = 0.0, + .force_tdd = false}; + +struct cells { + srsran_nbiot_cell_t cell; + float freq; + int dl_earfcn; + float power; +}; +struct cells results[1024]; + +float rf_gain = 70.0; +char* rf_args = ""; +bool scan_raster_offset = false; + +void usage(char* prog) +{ + printf("Usage: %s [agsendtvb] -b band\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-g RF gain [Default %.2f dB]\n", rf_gain); + printf("\t-s earfcn_start [Default All]\n"); + printf("\t-e earfcn_end [Default All]\n"); + printf("\t-r Also scan frequencies with raster offset [Default %s]\n", scan_raster_offset ? "Yes" : "No"); + printf("\t-n nof_frames_total [Default 100]\n"); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "agserndvb")) != -1) { + switch (opt) { + case 'a': + rf_args = argv[optind]; + break; + case 'b': + band = (int)strtol(argv[optind], NULL, 10); + break; + case 's': + earfcn_start = (int)strtol(argv[optind], NULL, 10); + break; + case 'e': + earfcn_end = (int)strtol(argv[optind], NULL, 10); + break; + case 'n': + cell_detect_config.max_frames_pss = (int)strtol(argv[optind], NULL, 10); + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'r': + scan_raster_offset = true; + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (band == -1) { + usage(argv[0]); + exit(-1); + } +} + +int srsran_rf_recv_wrapper(void* h, cf_t* data[SRSRAN_MAX_PORTS], uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + void* ptr[SRSRAN_MAX_PORTS]; + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + ptr[i] = data[i]; + } + return srsran_rf_recv_with_time_multi(h, ptr, nsamples, true, NULL, NULL); +} + +bool go_exit = false; + +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } +} + +static SRSRAN_AGC_CALLBACK(srsran_rf_set_rx_gain_wrapper) +{ + srsran_rf_set_rx_gain((srsran_rf_t*)h, gain_db); +} + +int main(int argc, char** argv) +{ + int n; + srsran_rf_t rf; + srsran_ue_cellsearch_nbiot_t cs; + srsran_nbiot_ue_cellsearch_result_t found_cells[3]; + int nof_freqs; + srsran_earfcn_t channels[MAX_EARFCN]; + uint32_t freq; + uint32_t n_found_cells = 0; + + parse_args(argc, argv); + + printf("Opening RF device...\n"); + if (srsran_rf_open(&rf, rf_args)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + if (!cell_detect_config.init_agc) { + srsran_rf_set_rx_gain(&rf, rf_gain); + } else { + printf("Starting AGC thread...\n"); + if (srsran_rf_start_gain_thread(&rf, false)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + srsran_rf_set_rx_gain(&rf, 50); + } + + // Supress RF messages + srsran_rf_suppress_stdout(&rf); + + nof_freqs = srsran_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); + if (nof_freqs < 0) { + fprintf(stderr, "Error getting EARFCN list\n"); + exit(-1); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + for (freq = 0; freq < nof_freqs && !go_exit; freq++) { + for (int i = 0; i < (scan_raster_offset ? NUM_RASTER_OFFSET : 1); i++) { + // set rf_freq + double rf_freq = channels[freq].fd * MHZ + raster_offset[i]; + srsran_rf_set_rx_freq(&rf, 0, rf_freq); + INFO("Set rf_freq to %.3f Hz", rf_freq); + + printf("[%3d/%d]: EARFCN %d, %.2f MHz looking for NPSS.\n", freq, nof_freqs, channels[freq].id, rf_freq / 1e6); + fflush(stdout); + + if (SRSRAN_VERBOSE_ISINFO()) { + printf("\n"); + } + + bzero(found_cells, 3 * sizeof(srsran_nbiot_ue_cellsearch_result_t)); + + if (srsran_ue_cellsearch_nbiot_init(&cs, cell_detect_config.max_frames_pss, srsran_rf_recv_wrapper, (void*)&rf)) { + fprintf(stderr, "Error initiating UE cell detect\n"); + exit(-1); + } + + if (cell_detect_config.max_frames_pss) { + srsran_ue_cellsearch_nbiot_set_nof_valid_frames(&cs, cell_detect_config.nof_valid_pss_frames); + } + if (cell_detect_config.init_agc) { + srsran_ue_sync_nbiot_start_agc(&cs.ue_sync, srsran_rf_set_rx_gain_wrapper, cell_detect_config.init_agc); + } + + INFO("Setting sampling frequency %.2f MHz for NPSS search", SRSRAN_CS_SAMP_FREQ / 1000000); + srsran_rf_set_rx_srate(&rf, SRSRAN_CS_SAMP_FREQ); + INFO("Starting receiver..."); + srsran_rf_start_rx_stream(&rf, false); + + n = srsran_ue_cellsearch_nbiot_scan(&cs); + if (n == SRSRAN_SUCCESS) { + srsran_rf_stop_rx_stream(&rf); + n = srsran_ue_cellsearch_nbiot_detect(&cs, found_cells); + if (n == SRSRAN_SUCCESS) { + srsran_nbiot_cell_t cell; + cell.n_id_ncell = found_cells[0].n_id_ncell; + cell.base.cp = SRSRAN_CP_NORM; + + // TODO: add MIB decoding + printf("Found CELL ID %d.\n", cell.n_id_ncell); + memcpy(&results[n_found_cells].cell, &cell, sizeof(srsran_nbiot_cell_t)); + results[n_found_cells].freq = channels[freq].fd; + results[n_found_cells].dl_earfcn = channels[freq].id; + results[n_found_cells].power = found_cells[0].peak; + n_found_cells++; + } else { + printf("Cell found but couldn't detect ID.\n"); + } + } + srsran_ue_cellsearch_nbiot_free(&cs); + } + } + + printf("\n\nFound %d cells\n", n_found_cells); + for (int i = 0; i < n_found_cells; i++) { + printf("Found CELL %.1f MHz, EARFCN=%d, PHYID=%d, NPSS power=%.1f dBm\n", + results[i].freq, + results[i].dl_earfcn, + results[i].cell.n_id_ncell, + 10 * log10(results[i].power)); + } + + printf("\nBye\n"); + + srsran_rf_close(&rf); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/npdsch_enodeb.c b/srsRAN_4G_mirror/lib/examples/npdsch_enodeb.c new file mode 100644 index 0000000..5d7d04c --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/npdsch_enodeb.c @@ -0,0 +1,730 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/phy/ch_estimation/chest_dl_nbiot.h" +#include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/io/filesink.h" +#include "srsran/phy/io/filesource.h" +#include "srsran/phy/sync/npss.h" +#include "srsran/phy/sync/nsss.h" +#include "srsran/phy/ue/ue_dl_nbiot.h" +#include "srsran/phy/utils/bit.h" +#include "srsran/phy/utils/random.h" + +#define UE_CRNTI 0x1234 + +#define HAVE_NPDSCH 1 +#define NPDCCH_SF_IDX 1 + +static const uint8_t dummy_sib1_payload[] = {0x43, 0x4d, 0xd0, 0x92, 0x22, 0x06, 0x04, 0x30, 0x28, + 0x6e, 0x87, 0xd0, 0x4b, 0x13, 0x90, 0xb4, 0x12, 0xa1, + 0x02, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +#ifndef DISABLE_RF +#include "srsran/phy/rf/rf.h" +static srsran_rf_t radio; +#else +#pragma message "Compiling npdsch_ue with no RF support" +#endif + +static char* output_file_name = NULL; + +static srsran_nbiot_cell_t cell = { + .base = {.nof_ports = 1, .nof_prb = SRSRAN_NBIOT_DEFAULT_NUM_PRB_BASECELL, .cp = SRSRAN_CP_NORM, .id = 0}, + .nbiot_prb = SRSRAN_NBIOT_DEFAULT_PRB_OFFSET, + .n_id_ncell = 0, + .nof_ports = 1, + .mode = SRSRAN_NBIOT_MODE_STANDALONE, + .is_r14 = true}; + +static uint32_t i_tbs_val = 1, last_i_tbs_val = 1; +static int nof_frames = -1; +static uint32_t i_sf_val = 0; +static uint32_t i_rep_val = 0; + +static char* rf_args = ""; +static float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 0; +static float file_snr = -100.0; + +static bool null_file_sink = false; +static srsran_random_t* random_gen; +static srsran_filesink_t fsink; +static srsran_ofdm_t ifft; +static srsran_npss_synch_t npss_sync; +static srsran_nsss_synch_t nsss_sync; +static srsran_npbch_t npbch; +static srsran_npdcch_t npdcch; +static srsran_npdsch_t npdsch; +static srsran_npdsch_cfg_t sib1_npdsch_cfg; +static srsran_npdsch_cfg_t npdsch_cfg; +static srsran_nbiot_ue_dl_t ue_dl; +static srsran_softbuffer_tx_t softbuffer; +static srsran_ra_nbiot_dl_dci_t ra_dl; +static srsran_ra_nbiot_dl_dci_t ra_dl_sib1; +static srsran_chest_dl_nbiot_t ch_est; +static srsran_mib_nb_t mib_nb; +static uint32_t sched_info_tag = + 0; // according to Table 16.4.1.3-3 in 36.213, 0 means 4 NPDSCH repetitions with TBS 208 + +static cf_t *sf_buffer = NULL, *output_buffer = NULL; +static int sf_n_re = 0, sf_n_samples = 0; + +void usage(char* prog) +{ + printf("Usage: %s [agmiftlReosncvrpu]\n", prog); +#ifndef DISABLE_RF + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-e RF amplitude [Default %.2f]\n", rf_amp); + printf("\t-g RF TX gain [Default %.2f dB]\n", rf_gain); + printf("\t-f RF TX frequency [Default %.1f MHz]\n", rf_freq / 1000000); +#else + printf("\t RF is disabled.\n"); +#endif + printf("\t-o output_file [Default use RF board]\n"); + printf("\t-s SNR-10 (only if output to file) [Default %f]\n", file_snr); + printf("\t-t Value of schedulingInfoSIB1-NB-r13 [Default %d]\n", sched_info_tag); + printf("\t-m Value of i_tbs (translates to MCS) [Default %d]\n", i_tbs_val); + printf("\t-i Value of i_sf [Default %d]\n", i_sf_val); + printf("\t-r Value of i_rep [Default %d]\n", i_rep_val); + printf("\t-n number of frames [Default %d]\n", nof_frames); + printf("\t-l n_id_ncell [Default %d]\n", cell.n_id_ncell); + printf("\t-R Is R14 cell [Default %s]\n", cell.is_r14 ? "Yes" : "No"); + printf("\t-p NB-IoT PRB id [Default %d]\n", cell.nbiot_prb); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "aglfmiosncrtvpuR")) != -1) { + switch (opt) { + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'e': + rf_amp = strtof(argv[optind], NULL); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'o': + output_file_name = argv[optind]; + break; + case 's': + file_snr = strtof(argv[optind], NULL); + break; + case 't': + sched_info_tag = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'm': + i_tbs_val = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'i': + i_sf_val = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'r': + i_rep_val = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'n': + nof_frames = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'l': + cell.n_id_ncell = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'R': + cell.is_r14 = !cell.is_r14; + break; + case 'p': + cell.nbiot_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + + if (!output_file_name && rf_freq == 0) { + usage(argv[0]); + printf("\nError! Either RF frequency or output filename need to be specified.\n"); + exit(-1); + } + +#ifdef DISABLE_RF + if (!output_file_name) { + usage(argv[0]); + exit(-1); + } +#endif +} + +void base_init() +{ + // init memory + sf_buffer = srsran_vec_cf_malloc(sf_n_re); + if (!sf_buffer) { + perror("malloc"); + exit(-1); + } + output_buffer = srsran_vec_cf_malloc(sf_n_samples); + if (!output_buffer) { + perror("malloc"); + exit(-1); + } + // open file or USRP + if (output_file_name) { + if (strcmp(output_file_name, "NULL")) { + if (srsran_filesink_init(&fsink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", output_file_name); + exit(-1); + } + null_file_sink = false; + } else { + null_file_sink = true; + } + } else { +#ifndef DISABLE_RF + printf("Opening RF device...\n"); + if (srsran_rf_open(&radio, rf_args)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } +#else + printf("Error RF not available. Select an output file\n"); + exit(-1); +#endif + } + + if (srsran_ofdm_tx_init(&ifft, SRSRAN_CP_NORM, sf_buffer, output_buffer, cell.base.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + srsran_ofdm_set_normalize(&ifft, true); + srsran_ofdm_set_freq_shift(&ifft, -SRSRAN_NBIOT_FREQ_SHIFT_FACTOR); + + if (srsran_npss_synch_init(&npss_sync, sf_n_samples, srsran_symbol_sz(cell.base.nof_prb))) { + fprintf(stderr, "Error initializing NPSS object\n"); + exit(-1); + } + + if (srsran_nsss_synch_init(&nsss_sync, sf_n_samples, srsran_symbol_sz(cell.base.nof_prb))) { + fprintf(stderr, "Error initializing NSSS object\n"); + exit(-1); + } + + if (srsran_npbch_init(&npbch)) { + fprintf(stderr, "Error creating NPBCH object\n"); + exit(-1); + } + if (srsran_npbch_set_cell(&npbch, cell)) { + fprintf(stderr, "Error setting cell in NPBCH object\n"); + exit(-1); + } + + if (srsran_npdcch_init(&npdcch)) { + fprintf(stderr, "Error creating NPDCCH object\n"); + exit(-1); + } + + if (srsran_npdcch_set_cell(&npdcch, cell)) { + fprintf(stderr, "Configuring cell in NPDCCH\n"); + exit(-1); + } + + if (srsran_npdsch_init(&npdsch)) { + fprintf(stderr, "Error creating NPDSCH object\n"); + exit(-1); + } + + if (srsran_npdsch_set_cell(&npdsch, cell)) { + fprintf(stderr, "Configuring cell in NPDSCH\n"); + exit(-1); + } + srsran_npdsch_set_rnti(&npdsch, UE_CRNTI); + + if (srsran_softbuffer_tx_init(&softbuffer, cell.base.nof_prb)) { + fprintf(stderr, "Error initiating soft buffer\n"); + exit(-1); + } + + random_gen = srsran_random_init(time(NULL)); +} + +void base_free() +{ + srsran_random_free(random_gen); + srsran_softbuffer_tx_free(&softbuffer); + srsran_npdsch_free(&npdsch); + srsran_npdcch_free(&npdcch); + srsran_npbch_free(&npbch); + srsran_chest_dl_nbiot_free(&ch_est); + srsran_npss_synch_free(&npss_sync); + srsran_nsss_synch_free(&nsss_sync); + srsran_ofdm_tx_free(&ifft); + + if (sf_buffer) { + free(sf_buffer); + } + if (output_buffer) { + free(output_buffer); + } + if (output_file_name) { + if (!null_file_sink) { + srsran_filesink_free(&fsink); + } + } else { +#ifndef DISABLE_RF + srsran_rf_close(&radio); +#endif + } +} + +bool go_exit = false; +#ifndef DISABLE_RF +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } +} +#endif + +static int update_radl(void) +{ + bzero(&ra_dl_sib1, sizeof(srsran_ra_nbiot_dl_dci_t)); + + // NB-IoT specific fields + ra_dl_sib1.alloc.has_sib1 = true; + ra_dl_sib1.alloc.sched_info_sib1 = mib_nb.sched_info_sib1; + ra_dl_sib1.mcs_idx = 1; + + bzero(&ra_dl, sizeof(srsran_ra_nbiot_dl_dci_t)); + ra_dl.mcs_idx = i_tbs_val; + + // NB-IoT specific fields + ra_dl.format = 1; // FormatN1 DCI + ra_dl.alloc.has_sib1 = false; + ra_dl.alloc.is_ra = false; + ra_dl.alloc.i_delay = 0; + ra_dl.alloc.i_sf = i_sf_val; + ra_dl.alloc.i_rep = i_rep_val; + ra_dl.alloc.harq_ack = 1; + ra_dl.alloc.i_n_start = 0; + + srsran_nbiot_dl_dci_fprint(stdout, &ra_dl); + srsran_ra_nbiot_dl_grant_t dummy_grant; + srsran_ra_nbits_t dummy_nbits; + +#define DUMMY_SFIDX 1 +#define DUMMY_SFN 0 + srsran_ra_nbiot_dl_dci_to_grant(&ra_dl, &dummy_grant, DUMMY_SFN, DUMMY_SFIDX, DUMMY_R_MAX, false, cell.mode); + srsran_ra_nbiot_dl_grant_to_nbits(&dummy_grant, cell, 0, &dummy_nbits); + srsran_ra_nbiot_dl_grant_fprint(stdout, &dummy_grant); + printf("Type new MCS index and press Enter: "); + fflush(stdout); + + return SRSRAN_SUCCESS; +} + +/* Read new MCS from stdin */ +static int update_control(void) +{ + char input[128]; + + fd_set set; + FD_ZERO(&set); + FD_SET(0, &set); + + struct timeval to; + to.tv_sec = 0; + to.tv_usec = 0; + + int n = select(1, &set, NULL, NULL, &to); + if (n == 1) { + // stdin ready + if (fgets(input, sizeof(input), stdin)) { + last_i_tbs_val = i_tbs_val; + i_tbs_val = atoi(input); + bzero(input, sizeof(input)); + if (update_radl()) { + printf("Trying with last known MCS index\n"); + i_tbs_val = last_i_tbs_val; + return update_radl(); + } + } + return 0; + } else if (n < 0) { + // error + perror("select"); + return -1; + } else { + return 0; + } +} + +#define DATA_BUFF_SZ 1024 * 128 +uint8_t data[8 * DATA_BUFF_SZ] = {}; +uint8_t data2[DATA_BUFF_SZ] = {}; +uint8_t data_tmp[DATA_BUFF_SZ] = {}; + +int main(int argc, char** argv) +{ + int nf = 0, sf_idx = 0; + cf_t npss_signal[SRSRAN_NPSS_TOT_LEN]; + cf_t nsss_signal[SRSRAN_NSSS_LEN * SRSRAN_NSSS_NUM_SEQ]; // for subframe 9 + + uint8_t bch_payload[SRSRAN_MIB_NB_LEN]; + uint8_t sib1_nb_payload[SRSRAN_NPDSCH_MAX_TBS]; + + srsran_dci_msg_t dci_msg; + srsran_dci_location_t locations[SRSRAN_NOF_SF_X_FRAME][30]; + + uint32_t sfn = 0; + uint32_t hfn = 0; // Hyper frame number is incremented when sfn wraps and is also 10bit wide + +#ifdef DISABLE_RF + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc, argv); + + // adjust SNR input to allow for negative values + if (output_file_name && file_snr != -100.0) { + file_snr -= 10.0; + printf("Target SNR: %.2fdB\n", file_snr); + } + + sf_n_re = 2 * SRSRAN_CP_NORM_NSYMB * cell.base.nof_prb * SRSRAN_NRE; + sf_n_samples = 2 * SRSRAN_SLOT_LEN(srsran_symbol_sz(cell.base.nof_prb)); + + /* this *must* be called after setting slot_len_* */ + base_init(); + + // buffer for outputting signal in RE representation (using sf_n_re) + cf_t* sf_re_symbols[SRSRAN_MAX_PORTS] = {NULL, NULL, NULL, NULL}; + sf_re_symbols[0] = sf_buffer; + + // buffer for outputting actual IQ samples (using sf_n_samples) + cf_t* sf_symbols[SRSRAN_MAX_PORTS] = {NULL, NULL, NULL, NULL}; + sf_symbols[0] = output_buffer; + + // construct MIB-NB + mib_nb.sched_info_sib1 = sched_info_tag; + mib_nb.sys_info_tag = 0; + mib_nb.ac_barring = false; + mib_nb.mode = SRSRAN_NBIOT_MODE_STANDALONE; + + // Initialize UE DL + if (srsran_nbiot_ue_dl_init(&ue_dl, sf_symbols, SRSRAN_NBIOT_MAX_PRB, SRSRAN_NBIOT_NUM_RX_ANTENNAS)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + + if (srsran_nbiot_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Setting cell in UE DL\n"); + return -1; + } + + srsran_nbiot_ue_dl_set_mib(&ue_dl, mib_nb); + + /* Generate NPSS/NSSS signals */ + srsran_npss_generate(npss_signal); + srsran_nsss_generate(nsss_signal, cell.n_id_ncell); + +#ifdef NPSS_DUMP + srsran_filesink_t debug_fsink; + char fname[] = "npss.bin"; + if (srsran_filesink_init(&debug_fsink, fname, SRSRAN_COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", fname); + exit(-1); + } + srsran_filesink_write(&debug_fsink, npss_signal, SRSRAN_NPSS_LEN * 11); + srsran_filesink_free(&debug_fsink); +#endif + + /* Generate CRS+NRS signals */ + if (srsran_chest_dl_nbiot_init(&ch_est, SRSRAN_NBIOT_MAX_PRB)) { + fprintf(stderr, "Error initializing equalizer\n"); + exit(-1); + } + if (srsran_chest_dl_nbiot_set_cell(&ch_est, cell) != SRSRAN_SUCCESS) { + fprintf(stderr, "Error setting channel estimator's cell configuration\n"); + return -1; + } + +#ifndef DISABLE_RF + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + if (!output_file_name) { + int srate = srsran_sampling_freq_hz(cell.base.nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + float srate_rf = srsran_rf_set_tx_srate(&radio, (double)srate); + if (srate_rf != srate) { + fprintf(stderr, "Could not set sampling rate\n"); + exit(-1); + } + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell.base.nof_prb); + exit(-1); + } + srsran_rf_set_tx_gain(&radio, rf_gain); + printf("Set TX gain: %.1f dB\n", srsran_rf_get_tx_gain(&radio)); + printf("Set TX freq: %.2f MHz\n", srsran_rf_set_tx_freq(&radio, 0, rf_freq) / 1000000); + } +#endif + + if (update_radl()) { + exit(-1); + } + + /* Initiate valid DCI locations */ + for (int i = 0; i < SRSRAN_NOF_SF_X_FRAME; i++) { + locations[i][0].L = 1; // Agg-level 2, i.e. both NCEEs used + locations[i][0].ncce = 0; + } + + nf = 0; + + bool send_data = false; + bool npdsch_active = false; + srsran_softbuffer_tx_reset(&softbuffer); + bzero(&sib1_npdsch_cfg, sizeof(srsran_npdsch_cfg_t)); + bzero(&npdsch_cfg, sizeof(srsran_npdsch_cfg_t)); + +#ifndef DISABLE_RF + bool start_of_burst = true; +#endif + + while ((nf < nof_frames || nof_frames == -1) && !go_exit) { + for (sf_idx = 0; sf_idx < SRSRAN_NOF_SF_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { + srsran_vec_cf_zero(sf_buffer, sf_n_re); + + // Transmit NPBCH in subframe 0 + if (sf_idx == 0) { + if ((sfn % SRSRAN_NPBCH_NUM_FRAMES) == 0) { + srsran_npbch_mib_pack(hfn, sfn, mib_nb, bch_payload); + } + srsran_npbch_put_subframe(&npbch, bch_payload, sf_re_symbols, sfn); + if (SRSRAN_VERBOSE_ISDEBUG()) { + printf("MIB payload: "); + srsran_vec_fprint_hex(stdout, bch_payload, SRSRAN_MIB_NB_LEN); + } + } + + // Transmit NPSS, NSSS and NRS + if (sf_idx == 5) { + // NPSS at subframe 5 + srsran_npss_put_subframe(&npss_sync, npss_signal, sf_buffer, cell.base.nof_prb, cell.nbiot_prb); + } else if ((sfn % 2 == 0) && sf_idx == 9) { + // NSSS in every even numbered frame at subframe 9 + srsran_nsss_put_subframe(&nsss_sync, nsss_signal, sf_buffer, sfn, cell.base.nof_prb, cell.nbiot_prb); + } else { + // NRS in all other subframes (using CSR signal intentionally) + // DEBUG("%d.%d: Putting %d NRS pilots", sfn, sf_idx, SRSRAN_REFSIGNAL_NUM_SF(1, cell.nof_ports)); + srsran_refsignal_nrs_put_sf(cell, 0, ch_est.nrs_signal.pilots[0][sf_idx], sf_buffer); + } + +#if HAVE_NPDSCH + // only transmit in subframes not used for NPBCH, NPSS or NSSS and only use subframe 4 when there is no SIB1 + // transmission + if (sf_idx != 0 && sf_idx != 5 && (!(sf_idx == 9 && sfn % 2 == 0)) && + !srsran_nbiot_ue_dl_is_sib1_sf(&ue_dl, sfn, sf_idx)) { + send_data = true; + } else { + send_data = false; + } + + // SIB1-NB content + if (hfn % 4 == 0 && sfn == 0 && sf_idx == 0) { + // copy captured SIB1 + memcpy(sib1_nb_payload, dummy_sib1_payload, sizeof(dummy_sib1_payload)); + + // overwrite Hyper Frame Number (HFN), 8 MSB + uint8_t unpacked_hfn[4 * 8]; + srsran_bit_unpack_vector(sib1_nb_payload, unpacked_hfn, 4 * 8); + uint8_t* tmp = unpacked_hfn; + tmp += 12; + srsran_bit_unpack(hfn >> 2, &tmp, 8); + uint8_t packed_hfn[4]; + srsran_bit_pack_vector(unpacked_hfn, packed_hfn, 32); + memcpy(sib1_nb_payload, packed_hfn, sizeof(packed_hfn)); + + if (SRSRAN_VERBOSE_ISDEBUG()) { + printf("SIB1-NB payload: "); + srsran_vec_fprint_byte(stdout, sib1_nb_payload, sizeof(dummy_sib1_payload)); + } + } + + if (srsran_nbiot_ue_dl_is_sib1_sf(&ue_dl, sfn, sf_idx)) { + INFO("%d.%d: Transmitting SIB1-NB.", sfn, sf_idx); + assert(send_data == false); + + // configure DL grant for SIB1-NB transmission + if (sib1_npdsch_cfg.sf_idx == 0) { + srsran_ra_nbiot_dl_grant_t grant; + srsran_ra_nbiot_dl_dci_to_grant(&ra_dl_sib1, &grant, sfn, sf_idx, DUMMY_R_MAX, true, cell.mode); + if (srsran_npdsch_cfg(&sib1_npdsch_cfg, cell, &grant, sf_idx)) { + fprintf(stderr, "Error configuring NPDSCH\n"); + exit(-1); + } + } + + // Encode SIB1 content + if (srsran_npdsch_encode_rnti( + &npdsch, &sib1_npdsch_cfg, &softbuffer, sib1_nb_payload, SRSRAN_SIRNTI, sf_re_symbols)) { + fprintf(stderr, "Error encoding NPDSCH\n"); + exit(-1); + } + + if (sib1_npdsch_cfg.sf_idx == sib1_npdsch_cfg.grant.nof_sf) { + bzero(&sib1_npdsch_cfg, sizeof(srsran_npdsch_cfg_t)); + } + } + + // Update DL resource allocation from control port + if (update_control()) { + fprintf(stderr, "Error updating parameters from control port\n"); + } + + if (send_data) { + // always transmit NPDCCH on fixed positions if no transmission is going on + if (sf_idx == NPDCCH_SF_IDX && !npdsch_active) { + // Encode NPDCCH + INFO("Putting DCI to location: n=%d, L=%d", locations[sf_idx][0].ncce, locations[sf_idx][0].L); + srsran_dci_msg_pack_npdsch(&ra_dl, SRSRAN_DCI_FORMATN1, &dci_msg, false); + if (srsran_npdcch_encode(&npdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_re_symbols, sf_idx)) { + fprintf(stderr, "Error encoding DCI message\n"); + exit(-1); + } + + // Configure NPDSCH accordingly + srsran_ra_nbiot_dl_grant_t grant; + srsran_ra_nbiot_dl_dci_to_grant(&ra_dl, &grant, sfn, sf_idx, DUMMY_R_MAX, false, cell.mode); + if (srsran_npdsch_cfg(&npdsch_cfg, cell, &grant, sf_idx)) { + fprintf(stderr, "Error configuring NPDSCH\n"); + exit(-1); + } + } + + // catch start of "user" NPDSCH + if (!npdsch_active && (sf_idx == npdsch_cfg.grant.start_sfidx && sfn == npdsch_cfg.grant.start_sfn)) { + // generate data only in first sf + INFO("%d.%d: Generating %d random bits", sfn, sf_idx, npdsch_cfg.grant.mcs[0].tbs); + for (int i = 0; i < npdsch_cfg.grant.mcs[0].tbs / 8; i++) { + data[i] = srsran_random_uniform_int_dist(random_gen, 0, 255); + } + if (SRSRAN_VERBOSE_ISDEBUG()) { + printf("Tx payload: "); + srsran_vec_fprint_b(stdout, data, npdsch_cfg.grant.mcs[0].tbs / 8); + } + npdsch_active = true; + } + + if (npdsch_active) { + DEBUG("Current sf_idx=%d, Encoding npdsch.sf_idx=%d start=%d, nof=%d", + sf_idx, + npdsch_cfg.sf_idx, + npdsch_cfg.grant.start_sfidx, + npdsch_cfg.grant.nof_sf); + // Encode NPDSCH + if (srsran_npdsch_encode(&npdsch, &npdsch_cfg, &softbuffer, data, sf_re_symbols)) { + fprintf(stderr, "Error encoding NPDSCH\n"); + exit(-1); + } + if (npdsch_cfg.num_sf == npdsch_cfg.grant.nof_sf * npdsch_cfg.grant.nof_rep) { + INFO("Deactive current NPDSCH"); + npdsch_active = false; + } + } + } +#endif + + /* Transform to OFDM symbols */ + srsran_ofdm_tx_sf(&ifft); + + if (output_file_name && file_snr != -100.0) { + // compute average energy per symbol + float abs_avg = srsran_vec_avg_power_cf(output_buffer, sf_n_samples); + + // find the noise spectral density + float snr_lin = srsran_convert_dB_to_power(file_snr); + float n0 = abs_avg / snr_lin; + float nstd = sqrtf(n0 / 2); + + // add some noise to the signal + srsran_ch_awgn_c(output_buffer, output_buffer, nstd, sf_n_samples); + } + + /* send to file or usrp */ + if (output_file_name) { + // write to file + if (!null_file_sink) { + srsran_filesink_write(&fsink, output_buffer, sf_n_samples); + } + usleep(1000); + } else { +#ifndef DISABLE_RF + // TODO: output scaling needed? + srsran_rf_send2(&radio, output_buffer, sf_n_samples, true, start_of_burst, false); + start_of_burst = false; +#endif + } + } + nf++; + sfn++; + if (sfn >= 1024) { + sfn = 0; + hfn = (hfn + 1) % 1024; + printf("NB-IoT HFN: %d\n", hfn); + } + } + + base_free(); + + printf("Done\n"); + + return SRSRAN_SUCCESS; +} diff --git a/srsRAN_4G_mirror/lib/examples/npdsch_ue.c b/srsRAN_4G_mirror/lib/examples/npdsch_ue.c new file mode 100644 index 0000000..3dcebfb --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/npdsch_ue.c @@ -0,0 +1,1086 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "npdsch_ue_helper.h" +#include "srsran/phy/ch_estimation/chest_dl_nbiot.h" +#include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/io/filesink.h" +#include "srsran/phy/io/filesource.h" +#include "srsran/phy/ue/ue_dl_nbiot.h" +#include "srsran/phy/ue/ue_mib_nbiot.h" +#include "srsran/phy/ue/ue_sync_nbiot.h" +#include "srsran/phy/utils/bit.h" + +#undef ENABLE_AGC_DEFAULT + +#ifndef DISABLE_RF +#include "srsran/phy/rf/rf.h" +#include "srsran/phy/rf/rf_utils.h" + +#define ENABLE_MANUAL_NSSS_SEARCH 0 +#define HAVE_PCAP 1 + +#if HAVE_PCAP +#include "srsran/common/pcap.h" +#endif + +cell_search_cfg_t cell_detect_config = {.max_frames_pbch = SRSRAN_DEFAULT_MAX_FRAMES_NPBCH, + .max_frames_pss = SRSRAN_DEFAULT_MAX_FRAMES_NPSS, + .nof_valid_pss_frames = SRSRAN_DEFAULT_NOF_VALID_NPSS_FRAMES, + .init_agc = 0, + .force_tdd = false}; + +#else +#pragma message "Compiling npdsch_ue with no RF support" +#endif + +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +void init_plots(); +pthread_t plot_thread; +sem_t plot_sem; +uint32_t plot_sf_idx = 0; +bool plot_track = true; +#define HAVE_RSRP_PLOT 0 +#endif // ENABLE_GUI + +#define PRINT_CHANGE_SCHEDULIGN +#define NPSS_FIND_PLOT_WIDTH 80 +//#define CORRECT_SAMPLE_OFFSET + +static srsran_nbiot_si_params_t sib2_params; + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + int nof_subframes; + bool disable_plots; + bool disable_plots_except_constellation; + bool disable_cfo; + uint32_t time_offset; + int n_id_ncell; + bool is_r14; + bool skip_sib2; + uint16_t rnti; + char* input_file_name; + int file_offset_time; + float file_offset_freq; + uint32_t file_nof_prb; + uint32_t file_nof_ports; + uint32_t file_cell_id; + char* rf_dev; + char* rf_args; + double rf_freq; + float rf_gain; +} prog_args_t; + +void args_default(prog_args_t* args) +{ + args->disable_plots = false; + args->disable_plots_except_constellation = false; + args->nof_subframes = -1; + args->rnti = SRSRAN_SIRNTI; + args->n_id_ncell = SRSRAN_CELL_ID_UNKNOWN; + args->is_r14 = true; + args->input_file_name = NULL; + args->disable_cfo = false; + args->time_offset = 0; + args->file_nof_prb = 1; + args->file_nof_ports = 0; + args->file_cell_id = 0; + args->file_offset_time = 0; + args->file_offset_freq = 0; + args->rf_dev = ""; + args->rf_args = ""; + args->rf_freq = -1.0; +#ifdef ENABLE_AGC_DEFAULT + args->rf_gain = -1.0; +#else + args->rf_gain = 70.0; +#endif +} + +void usage(prog_args_t* args, char* prog) +{ + printf("Usage: %s [agpRPoOildtDnrBuHvqwzxc] -f rx_frequency (in Hz) | -i input_file\n", prog); +#ifndef DISABLE_RF + printf("\t-I RF dev [Default %s]\n", args->rf_dev); + printf("\t-a RF args [Default %s]\n", args->rf_args); + +#ifdef ENABLE_AGC_DEFAULT + printf("\t-g RF fix RX gain [Default AGC]\n"); +#else + printf("\t-g Set RX gain [Default %.1f dB]\n", args->rf_gain); +#endif +#else + printf("\t RF is disabled.\n"); +#endif + printf("\t-i input_file [Default use RF board]\n"); + printf("\t-o offset frequency correction (in Hz) for input file [Default %.1f Hz]\n", args->file_offset_freq); + printf("\t-O offset samples for input file [Default %d]\n", args->file_offset_time); + printf("\t-p nof_prb for input file [Default %d]\n", args->file_nof_prb); + printf("\t-P nof_ports for input file [Default %d]\n", args->file_nof_ports); + printf("\t-r RNTI in Hex [Default 0x%x]\n", args->rnti); + printf("\t-l n_id_ncell [Default %d]\n", args->n_id_ncell); + printf("\t-R Is R14 cell [Default %s]\n", args->is_r14 ? "Yes" : "No"); + printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo ? "Disabled" : "Enabled"); + printf("\t-t Add time offset [Default %d]\n", args->time_offset); + printf("\t-s Skip SIB2 decoding[Default %d]\n", args->skip_sib2); +#ifdef ENABLE_GUI + printf("\t-d disable plots [Default enabled]\n"); + printf("\t-D disable all but constellation plots [Default enabled]\n"); +#else + printf("\t plots are disabled. Graphics library not available\n"); +#endif // ENABLE_GUI + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +void parse_args(prog_args_t* args, int argc, char** argv) +{ + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "aogRBliIpHPOCtdDsnvrfqwzxc")) != -1) { + switch (opt) { + case 'i': + args->input_file_name = argv[optind]; + break; + case 'p': + args->file_nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'P': + args->file_nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'o': + args->file_offset_freq = strtof(argv[optind], NULL); + break; + case 'O': + args->file_offset_time = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'I': + args->rf_dev = argv[optind]; + break; + case 'a': + args->rf_args = argv[optind]; + break; + case 'g': + args->rf_gain = strtof(argv[optind], NULL); + break; + case 'C': + args->disable_cfo = true; + break; + case 't': + args->time_offset = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'f': + args->rf_freq = strtod(argv[optind], NULL); + break; + case 'n': + args->nof_subframes = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'r': + args->rnti = strtol(argv[optind], NULL, 16); + break; + case 'l': + args->n_id_ncell = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'R': + args->is_r14 = !args->is_r14; + break; + case 'd': + args->disable_plots = true; + break; + case 's': + args->skip_sib2 = !args->skip_sib2; + break; + case 'D': + args->disable_plots_except_constellation = true; + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_freq < 0 && args->input_file_name == NULL) { + usage(args, argv[0]); + exit(-1); + } +} +/**********************************************************************/ + +static uint8_t rx_tb[SRSRAN_MAX_DL_BITS_CAT_NB1]; // Byte buffer for rx'ed transport blocks + +bool go_exit = false; +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } +} + +#if HAVE_PCAP +void pcap_pack_and_write(FILE* pcap_file, + uint8_t* pdu, + uint32_t pdu_len_bytes, + uint8_t reTX, + bool crc_ok, + uint32_t tti, + uint16_t crnti, + uint8_t direction, + uint8_t rnti_type) +{ + MAC_Context_Info_t context = {.radioType = FDD_RADIO, + .direction = direction, + .rntiType = rnti_type, + .rnti = crnti, + .ueid = 1, + .isRetx = reTX, + .crcStatusOK = crc_ok, + .sysFrameNumber = (uint16_t)(tti / SRSRAN_NOF_SF_X_FRAME), + .subFrameNumber = (uint16_t)(tti % SRSRAN_NOF_SF_X_FRAME), + .nbiotMode = 1}; + if (pdu) { + LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } +} +#endif + +#ifndef DISABLE_RF +int srsran_rf_recv_wrapper(void* h, void* data, uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + return srsran_rf_recv_with_time(h, data, nsamples, true, &t->full_secs, &t->frac_secs); +} + +void srsran_rf_set_rx_gain_th_wrapper_(void* h, float f) +{ + srsran_rf_set_rx_gain_th((srsran_rf_t*)h, f); +} + +#endif + +enum receiver_state { DECODE_MIB, DECODE_SIB, DECODE_NPDSCH } state; + +static srsran_nbiot_cell_t cell = {}; + +srsran_nbiot_ue_dl_t ue_dl; +srsran_nbiot_ue_sync_t ue_sync; +prog_args_t prog_args; + +bool have_sib1 = false; +bool have_sib2 = false; + +#ifdef ENABLE_GUI +#define MAX_MSG_BUF (8192) +static char mib_buffer_disp[MAX_MSG_BUF], mib_buffer_decode[MAX_MSG_BUF]; +static char sib1_buffer_disp[MAX_MSG_BUF], sib1_buffer_decode[MAX_MSG_BUF]; +static char sib2_buffer_disp[MAX_MSG_BUF], sib2_buffer_decode[MAX_MSG_BUF]; + +#if HAVE_RSRP_PLOT +#define RSRP_TABLE_MAX_IDX 1024 +static float rsrp_table[RSRP_TABLE_MAX_IDX]; +static uint32_t rsrp_table_index = 0; +static uint32_t rsrp_num_plot = RSRP_TABLE_MAX_IDX; +#endif // HAVE_RSRP_PLOT +#endif // ENABLE_GUI + +static uint32_t system_frame_number = 0; +static uint32_t hyper_frame_number = 0; + +int main(int argc, char** argv) +{ + int ret; + int64_t sf_cnt; + srsran_ue_mib_nbiot_t ue_mib; +#ifndef DISABLE_RF + srsran_rf_t rf; +#endif + uint32_t nof_trials = 0; + int n; + uint8_t bch_payload[SRSRAN_MIB_NB_LEN] = {}; + int sfn_offset; + float cfo = 0; + + parse_args(&prog_args, argc, argv); + +#if HAVE_PCAP + FILE* pcap_file = DLT_PCAP_Open(MAC_LTE_DLT, "/tmp/npdsch.pcap"); +#endif + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + cell.base.nof_prb = SRSRAN_NBIOT_DEFAULT_NUM_PRB_BASECELL; + cell.nbiot_prb = SRSRAN_NBIOT_DEFAULT_PRB_OFFSET; + cell.n_id_ncell = prog_args.n_id_ncell; + cell.is_r14 = prog_args.is_r14; + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + printf("Opening RF device...\n"); + if (srsran_rf_open_devname(&rf, prog_args.rf_dev, prog_args.rf_args, 1)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + /* Set receiver gain */ + if (prog_args.rf_gain > 0) { + srsran_rf_set_rx_gain(&rf, prog_args.rf_gain); + printf("Set RX gain: %.1f dB\n", prog_args.rf_gain); + } else { + printf("Starting AGC thread...\n"); + if (srsran_rf_start_gain_thread(&rf, false)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + srsran_rf_set_rx_gain(&rf, 50); + cell_detect_config.init_agc = 50; + } + + // set transceiver frequency + printf("Set RX freq: %.6f MHz\n", srsran_rf_set_rx_freq(&rf, 0, prog_args.rf_freq) / 1000000); + + // set sampling frequency + int srate = srsran_sampling_freq_hz(cell.base.nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1e6); + double srate_rf = srsran_rf_set_rx_srate(&rf, srate); + printf("Actual sampling rate %.2f MHz\n", srate_rf / 1e6); + // We don't check the result rate with requested rate + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell.base.nof_prb); + exit(-1); + } + + INFO("Stopping RF and flushing buffer...\r"); + srsran_rf_stop_rx_stream(&rf); + +#if ENABLE_MANUAL_NSSS_SEARCH + // determine n_id_ncell + if (prog_args.n_id_ncell == SRSRAN_CELL_ID_UNKNOWN) { + srsran_nsss_synch_t nsss; + float nsss_peak_value; + int input_len = srate * 10 / 1000 * 2; // capture two full frames to make sure we have one NSSS + + cf_t* buffer = srsran_vec_cf_malloc(input_len * 2); + if (!buffer) { + perror("malloc"); + exit(-1); + } + + if (srsran_nsss_synch_init(&nsss, input_len, srate / 15000)) { + fprintf(stderr, "Error initializing NSSS object\n"); + exit(-1); + } + + srsran_rf_start_rx_stream(&rf, false); + n = srsran_rf_recv(&rf, buffer, input_len, 1); + if (n != input_len) { + fprintf(stderr, "Error receiving samples\n"); + exit(-1); + } + srsran_rf_stop_rx_stream(&rf); + + // trying to find NSSS + printf("Detecting NSSS signal .. "); + fflush(stdout); + uint32_t sfn_partial; + srsran_nsss_sync_find(&nsss, buffer, &nsss_peak_value, (uint32_t*)&cell.n_id_ncell, &sfn_partial); + printf("done!"); + srsran_nsss_synch_free(&nsss); + free(buffer); + } else { + cell.n_id_ncell = prog_args.n_id_ncell; + } + printf("\nSetting n_id_ncell to %d.\n", cell.n_id_ncell); +#else + if (cell.n_id_ncell == SRSRAN_CELL_ID_UNKNOWN) { + uint32_t ntrial = 0; + do { + ret = rf_cell_search_nbiot(&rf, &cell_detect_config, &cell, &cfo); + if (ret != SRSRAN_SUCCESS) { + printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); + } + } while (ret != SRSRAN_SUCCESS && !go_exit); + } +#endif + + if (go_exit) { + exit(0); + } + } +#endif + + /* If reading from file, go straight to PDSCH decoding. Otherwise, decode MIB first */ + if (prog_args.input_file_name) { + // set file specific params + cell.base.nof_ports = prog_args.file_nof_ports; + cell.nof_ports = prog_args.file_nof_ports; + + if (srsran_ue_sync_nbiot_init_file( + &ue_sync, cell, prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + } else { +#ifndef DISABLE_RF + if (srsran_ue_sync_nbiot_init(&ue_sync, cell, srsran_rf_recv_wrapper, (void*)&rf)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + // reduce AGC period to every 10th frame + srsran_ue_sync_nbiot_set_agc_period(&ue_sync, 10); +#endif + } + + // Allocate memory to fit a full frame (needed for time re-alignment) + cf_t* buff_ptrs[SRSRAN_MAX_PORTS] = {NULL}; + buff_ptrs[0] = srsran_vec_cf_malloc(SRSRAN_SF_LEN_PRB_NBIOT * 10); + + if (srsran_ue_mib_nbiot_init(&ue_mib, buff_ptrs, SRSRAN_NBIOT_MAX_PRB)) { + fprintf(stderr, "Error initaiting UE MIB decoder\n"); + exit(-1); + } + if (srsran_ue_mib_nbiot_set_cell(&ue_mib, cell) != SRSRAN_SUCCESS) { + fprintf(stderr, "Error setting cell configuration in UE MIB decoder\n"); + exit(-1); + } + + // Initialize subframe counter + sf_cnt = 0; + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + init_plots(); + } +#endif // ENABLE_GUI + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + srsran_rf_start_rx_stream(&rf, false); + } +#endif + + // Variables for measurements + uint32_t nframes = 0; + float rsrp = 0.0, rsrq = 0.0, noise = 0.0; + +#ifndef DISABLE_RF + if (prog_args.rf_gain < 0) { + srsran_ue_sync_nbiot_start_agc(&ue_sync, srsran_rf_set_rx_gain_th_wrapper_, cell_detect_config.init_agc); + } +#endif +#ifdef PRINT_CHANGE_SCHEDULIGN + srsran_ra_nbiot_dl_dci_t old_dl_dci; + bzero(&old_dl_dci, sizeof(srsran_ra_nbiot_dl_dci_t)); +#endif + + ue_sync.correct_cfo = !prog_args.disable_cfo; + + // Set initial CFO for ue_sync + srsran_ue_sync_nbiot_set_cfo(&ue_sync, cfo); + + srsran_npbch_decode_reset(&ue_mib.npbch); + + INFO("\nEntering main loop..."); + while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { + ret = srsran_ue_sync_nbiot_zerocopy_multi(&ue_sync, buff_ptrs); + if (ret < 0) { + fprintf(stderr, "Error calling srsran_nbiot_ue_sync_zerocopy_multi()\n"); + break; + } + +#ifdef CORRECT_SAMPLE_OFFSET + float sample_offset = + (float)srsran_ue_sync_get_last_sample_offset(&ue_sync) + srsran_ue_sync_get_sfo(&ue_sync) / 1000; + srsran_ue_dl_set_sample_offset(&ue_dl, sample_offset); +#endif + + // srsran_ue_sync_nbiot_zerocopy_multi() returns 1 if successfully read 1 aligned subframe + if (ret == 1) { + switch (state) { + case DECODE_MIB: + if (srsran_ue_sync_nbiot_get_sfidx(&ue_sync) == 0) { + n = srsran_ue_mib_nbiot_decode(&ue_mib, buff_ptrs[0], bch_payload, &cell.nof_ports, &sfn_offset); + if (n < 0) { + fprintf(stderr, "Error decoding UE MIB\n"); + exit(-1); + } else if (n == SRSRAN_UE_MIB_NBIOT_FOUND) { + printf("MIB received (CFO: %+6.2f kHz)\n", srsran_ue_sync_nbiot_get_cfo(&ue_sync) / 1000); + srsran_mib_nb_t mib; + srsran_npbch_mib_unpack(bch_payload, &mib); + + // update SFN and set deployment mode + system_frame_number = (mib.sfn + sfn_offset) % 1024; + cell.mode = mib.mode; + + // set number of ports of base cell to that of NB-IoT cell (TODO: read eutra-NumCRS-Ports-r13) + cell.base.nof_ports = cell.nof_ports; + + if (cell.mode == SRSRAN_NBIOT_MODE_INBAND_SAME_PCI) { + cell.base.id = cell.n_id_ncell; + } + + if (SRSRAN_VERBOSE_ISINFO()) { + srsran_mib_nb_printf(stdout, cell, &mib); + } + + // Initialize DL + if (srsran_nbiot_ue_dl_init(&ue_dl, buff_ptrs, SRSRAN_NBIOT_MAX_PRB, SRSRAN_NBIOT_NUM_RX_ANTENNAS)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + + if (srsran_nbiot_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Configuring cell in UE DL\n"); + exit(-1); + } + + // Configure downlink receiver with the MIB params and the RNTI we use + srsran_nbiot_ue_dl_set_mib(&ue_dl, mib); + srsran_nbiot_ue_dl_set_rnti(&ue_dl, prog_args.rnti); + + // Pretty-print MIB + srsran_bit_pack_vector(bch_payload, rx_tb, SRSRAN_MIB_NB_CRC_LEN); +#ifdef ENABLE_GUI + if (bcch_bch_to_pretty_string( + rx_tb, SRSRAN_MIB_NB_CRC_LEN, mib_buffer_decode, sizeof(mib_buffer_decode))) { + fprintf(stderr, "Error decoding MIB\n"); + } +#endif + +#if HAVE_PCAP + // write to PCAP + pcap_pack_and_write(pcap_file, + rx_tb, + SRSRAN_MIB_NB_CRC_LEN, + 0, + true, + system_frame_number * SRSRAN_NOF_SF_X_FRAME, + 0, + DIRECTION_DOWNLINK, + NO_RNTI); +#endif + // activate SIB1 decoding + srsran_nbiot_ue_dl_decode_sib1(&ue_dl, system_frame_number); + state = DECODE_SIB; + } + } + break; + + case DECODE_SIB: + if (!have_sib1) { + int dec_ret = srsran_nbiot_ue_dl_decode_npdsch(&ue_dl, + &buff_ptrs[0][prog_args.time_offset], + rx_tb, + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + SRSRAN_SIRNTI); + if (dec_ret == SRSRAN_SUCCESS) { + printf("SIB1 received\n"); + srsran_sys_info_block_type_1_nb_t sib = {}; + srsran_npdsch_sib1_unpack(rx_tb, &sib); + hyper_frame_number = sib.hyper_sfn; + + have_sib1 = true; + +#ifdef ENABLE_GUI + if (bcch_dl_sch_to_pretty_string( + rx_tb, ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, sib1_buffer_decode, sizeof(sib1_buffer_decode))) { + fprintf(stderr, "Error decoding SIB1\n"); + } +#endif + + // Decode SIB1 and extract SIB2 scheduling params + get_sib2_params(rx_tb, ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, &sib2_params); + + // Activate SIB2 decoding + srsran_nbiot_ue_dl_decode_sib( + &ue_dl, hyper_frame_number, system_frame_number, SRSRAN_NBIOT_SI_TYPE_SIB2, sib2_params); +#if HAVE_PCAP + pcap_pack_and_write(pcap_file, + rx_tb, + ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, + 0, + true, + system_frame_number * 10 + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + SRSRAN_SIRNTI, + DIRECTION_DOWNLINK, + SI_RNTI); +#endif + // if SIB1 was decoded in this subframe, skip processing it further + break; + } else if (dec_ret == SRSRAN_ERROR) { + // reactivate SIB1 grant + if (srsran_nbiot_ue_dl_has_grant(&ue_dl) == false) { + srsran_nbiot_ue_dl_decode_sib1(&ue_dl, system_frame_number); + } + } + } else if (!have_sib2 && !srsran_nbiot_ue_dl_is_sib1_sf( + &ue_dl, system_frame_number, srsran_ue_sync_nbiot_get_sfidx(&ue_sync))) { + // SIB2 is transmitted over multiple subframes, so this needs to be called more than once .. + int dec_ret = srsran_nbiot_ue_dl_decode_npdsch(&ue_dl, + &buff_ptrs[0][prog_args.time_offset], + rx_tb, + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + SRSRAN_SIRNTI); + if (dec_ret == SRSRAN_SUCCESS) { + printf("SIB2 received\n"); + have_sib2 = true; + +#ifdef ENABLE_GUI + if (bcch_dl_sch_to_pretty_string( + rx_tb, ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, sib2_buffer_decode, sizeof(sib2_buffer_decode))) { + fprintf(stderr, "Error decoding SIB2\n"); + } +#endif + +#if HAVE_PCAP + pcap_pack_and_write(pcap_file, + rx_tb, + ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, + 0, + true, + system_frame_number * 10 + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + SRSRAN_SIRNTI, + DIRECTION_DOWNLINK, + SI_RNTI); +#endif + } else { + // reactivate SIB2 grant + if (srsran_nbiot_ue_dl_has_grant(&ue_dl) == false) { + srsran_nbiot_ue_dl_decode_sib( + &ue_dl, hyper_frame_number, system_frame_number, SRSRAN_NBIOT_SI_TYPE_SIB2, sib2_params); + } + } + } + + if (have_sib1 && (have_sib2 || prog_args.skip_sib2)) { + if (prog_args.rnti == SRSRAN_SIRNTI) { + srsran_nbiot_ue_dl_decode_sib1(&ue_dl, system_frame_number); + } + state = DECODE_NPDSCH; + } + break; + case DECODE_NPDSCH: + if (prog_args.rnti != SRSRAN_SIRNTI) { + if (srsran_nbiot_ue_dl_has_grant(&ue_dl)) { + // attempt to decode NPDSCH + n = srsran_nbiot_ue_dl_decode_npdsch(&ue_dl, + &buff_ptrs[0][prog_args.time_offset], + rx_tb, + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + prog_args.rnti); + if (n == SRSRAN_SUCCESS) { + INFO("NPDSCH decoded ok."); + } + } else { + // decode NPDCCH + srsran_dci_msg_t dci_msg; + n = srsran_nbiot_ue_dl_decode_npdcch(&ue_dl, + &buff_ptrs[0][prog_args.time_offset], + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + prog_args.rnti, + &dci_msg); + if (n == SRSRAN_NBIOT_UE_DL_FOUND_DCI) { + INFO("DCI found for rnti=%d", prog_args.rnti); + // convert DCI to grant + srsran_ra_nbiot_dl_dci_t dci_unpacked; + srsran_ra_nbiot_dl_grant_t grant; + if (srsran_nbiot_dci_msg_to_dl_grant(&dci_msg, + prog_args.rnti, + &dci_unpacked, + &grant, + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + 64 /* TODO: remove */, + cell.mode)) { + fprintf(stderr, "Error unpacking DCI\n"); + return SRSRAN_ERROR; + } + // activate grant + srsran_nbiot_ue_dl_set_grant(&ue_dl, &grant); + } + } + } else { + // decode SIB1 over and over again + n = srsran_nbiot_ue_dl_decode_npdsch(&ue_dl, + &buff_ptrs[0][prog_args.time_offset], + rx_tb, + system_frame_number, + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + prog_args.rnti); + +#ifdef ENABLE_GUI + if (n == SRSRAN_SUCCESS) { + if (bcch_dl_sch_to_pretty_string( + rx_tb, ue_dl.npdsch_cfg.grant.mcs[0].tbs / 8, sib1_buffer_decode, sizeof(sib1_buffer_decode))) { + fprintf(stderr, "Error decoding SIB1\n"); + } + } +#endif // ENABLE_GUI + + // reactivate SIB1 grant + if (srsran_nbiot_ue_dl_has_grant(&ue_dl) == false) { + srsran_nbiot_ue_dl_decode_sib1(&ue_dl, system_frame_number); + } + } + + nof_trials++; + + rsrq = SRSRAN_VEC_EMA(srsran_chest_dl_nbiot_get_rsrq(&ue_dl.chest), rsrq, 0.1); + rsrp = SRSRAN_VEC_EMA(srsran_chest_dl_nbiot_get_rsrp(&ue_dl.chest), rsrp, 0.05); + noise = SRSRAN_VEC_EMA(srsran_chest_dl_nbiot_get_noise_estimate(&ue_dl.chest), noise, 0.05); + nframes++; + if (isnan(rsrq)) { + rsrq = 0; + } + if (isnan(noise)) { + noise = 0; + } + if (isnan(rsrp)) { + rsrp = 0; + } + + // Plot and Printf + if (srsran_ue_sync_nbiot_get_sfidx(&ue_sync) == 5) { + float gain = prog_args.rf_gain; + if (gain < 0) { + gain = 10 * log10(srsran_agc_get_gain(&ue_sync.agc)); + } + printf( + "CFO: %+6.2f kHz, RSRP: %4.1f dBm " + "SNR: %4.1f dB, RSRQ: %4.1f dB, " + "NPDCCH detected: %d, NPDSCH-BLER: %5.2f%% (%d of total %d), NPDSCH-Rate: %5.2f kbit/s\r", + srsran_ue_sync_nbiot_get_cfo(&ue_sync) / 1000, + 10 * log10(rsrp), + 10 * log10(rsrp / noise), + 10 * log10(rsrq), + ue_dl.nof_detected, + (float)100 * ue_dl.pkt_errors / ue_dl.pkts_total, + ue_dl.pkt_errors, + ue_dl.pkts_total, + (ue_dl.bits_total / ((system_frame_number * 10 + srsran_ue_sync_nbiot_get_sfidx(&ue_sync)) / 1000.0)) / + 1000.0); + } + break; + } + if (srsran_ue_sync_nbiot_get_sfidx(&ue_sync) == 9) { + system_frame_number++; + if (system_frame_number == 1024) { + system_frame_number = 0; + hyper_frame_number++; + printf("\n"); + + // don't reset counter when reading from file to maintain complete stats + if (!prog_args.input_file_name) { + ue_dl.pkt_errors = 0; + ue_dl.pkts_total = 0; + ue_dl.nof_detected = 0; + ue_dl.bits_total = 0; + nof_trials = 0; + } + } + } + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + if ((system_frame_number % 4) == 0) { + plot_sf_idx = srsran_ue_sync_nbiot_get_sfidx(&ue_sync); + plot_track = true; + sem_post(&plot_sem); + } + } +#endif // ENABLE_GUI + } else if (ret == 0) { + state = DECODE_MIB; + printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", + srsran_sync_nbiot_get_peak_value(&ue_sync.sfind), + ue_sync.frame_total_cnt, + ue_sync.state); +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + plot_sf_idx = srsran_ue_sync_nbiot_get_sfidx(&ue_sync); + plot_track = false; + sem_post(&plot_sem); + } +#endif // ENABLE_GUI + } + + sf_cnt++; + } // Main loop + + // print statistics + if (prog_args.input_file_name) { + printf("pkt_total=%d\n", ue_dl.pkts_total); + printf("pkt_ok=%d\n", ue_dl.pkts_total - ue_dl.pkt_errors); + printf("pkt_errors=%d\n", ue_dl.pkt_errors); + printf("bler=%.2f\n", ue_dl.pkts_total ? (float)100 * ue_dl.pkt_errors / ue_dl.pkts_total : 0); + printf("rate=%.2f\n", ((ue_dl.bits_total / ((sf_cnt) / 1000.0)) / 1000.0)); + printf("dci_detected=%d\n", ue_dl.nof_detected); + } + + srsran_nbiot_ue_dl_free(&ue_dl); + srsran_ue_sync_nbiot_free(&ue_sync); + +#if HAVE_PCAP + printf("Saving PCAP file\n"); + DLT_PCAP_Close(pcap_file); +#endif + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + srsran_ue_mib_nbiot_free(&ue_mib); + srsran_rf_close(&rf); + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + if (buff_ptrs[i] != NULL) + free(buff_ptrs[i]); + } + } +#endif + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + sem_post(&plot_sem); + if (!pthread_kill(plot_thread, 0)) { + pthread_kill(plot_thread, SIGHUP); + pthread_join(plot_thread, NULL); + } + } +#endif // ENABLE_GUI + + printf("\nBye\n"); + return SRSRAN_SUCCESS; +} + +/********************************************************************** + * Plotting Functions + ***********************************************************************/ +#ifdef ENABLE_GUI + +plot_real_t p_sync, pce; +#if HAVE_RSRP_PLOT +plot_real_t rsrp_plot; +#endif +plot_scatter_t constellation_plot; +text_edit_t miblog, sib1log, sib2log; +key_value_t id_label, mode_label, hfn_label; + +#define LABLE_MAX_LEN (10) +static char lable_buf[LABLE_MAX_LEN]; + +float tmp_plot[110 * 15 * 2048]; +float tmp_plot2[110 * 15 * 2048]; + +void* plot_thread_run(void* arg) +{ + uint32_t nof_re = SRSRAN_SF_LEN_RE(ue_dl.cell.base.nof_prb, ue_dl.cell.base.cp); +#if HAVE_RSRP_PLOT + float rsrp_lin = 0; +#endif + + sdrgui_init_title("Software Radio Systems NB-IoT Receiver"); + + plot_scatter_init(&constellation_plot); + plot_scatter_setTitle(&constellation_plot, "NPDCCH/NPDSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&constellation_plot, -2, 2); + plot_scatter_setYAxisScale(&constellation_plot, -2, 2); + + plot_scatter_addToWindowGrid(&constellation_plot, (char*)"npdsch_ue", 1, 0); + + if (!prog_args.disable_plots_except_constellation) { + plot_real_init(&pce); + plot_real_setTitle(&pce, "Channel Response - Magnitude"); + plot_real_setLabels(&pce, "Index", "dB"); + plot_real_setYAxisScale(&pce, -40, 40); + + plot_real_init(&p_sync); + plot_real_setTitle(&p_sync, "NPSS Cross-Corr abs value"); + plot_real_setYAxisScale(&p_sync, 0, 1); + +#if HAVE_RSRP_PLOT + plot_real_init(&rsrp_plot); + plot_real_setTitle(&rsrp_plot, "RSRP"); + plot_real_setLabels(&rsrp_plot, "subframe index", "dBm"); + plot_real_setYAxisScale(&rsrp_plot, 20, 50); +#endif + + plot_real_addToWindowGrid(&pce, (char*)"npdsch_ue", 1, 2); + plot_real_addToWindowGrid(&p_sync, (char*)"npdsch_ue", 1, 1); + +#if HAVE_RSRP_PLOT + plot_real_addToWindowGrid(&rsrp_plot, (char*)"npdsch_ue", 1, 3); +#endif + + // add log + text_edit_init(&miblog); + text_edit_addToWindowGrid(&miblog, (char*)"npdsch_ue", 2, 0); + text_edit_setTitle(&miblog, "Master Information Block - NB"); + + text_edit_init(&sib1log); + text_edit_addToWindowGrid(&sib1log, (char*)"npdsch_ue", 2, 1); + text_edit_setTitle(&sib1log, "System Information Block 1 - NB"); + + text_edit_init(&sib2log); + text_edit_addToWindowGrid(&sib2log, (char*)"npdsch_ue", 2, 2); + text_edit_setTitle(&sib2log, "System Information - NB"); + + key_value_init(&id_label); + text_edit_addToWindowGrid(&id_label, (char*)"npdsch_ue", 0, 0); + key_value_setKeyText(&id_label, "Cell ID:"); + + key_value_init(&mode_label); + text_edit_addToWindowGrid(&mode_label, (char*)"npdsch_ue", 0, 1); + key_value_setKeyText(&mode_label, "Operation Mode:"); + + key_value_init(&hfn_label); + text_edit_addToWindowGrid(&hfn_label, (char*)"npdsch_ue", 0, 2); + key_value_setKeyText(&hfn_label, "Hyper/System Frame Number:"); + } + + while (!go_exit) { + sem_wait(&plot_sem); + + if (!prog_args.disable_plots_except_constellation) { + for (int i = 0; i < nof_re; i++) { + tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + int numpoints = SRSRAN_NRE * 2; + bzero(tmp_plot2, sizeof(float) * numpoints); + int g = (numpoints - SRSRAN_NRE) / 2; + for (int i = 0; i < 12 * ue_dl.cell.base.nof_prb; i++) { + tmp_plot2[g + i] = 20 * log10(cabsf(ue_dl.ce[0][i])); + if (isinf(tmp_plot2[g + i])) { + tmp_plot2[g + i] = -80; + } + } + plot_real_setNewData(&pce, tmp_plot2, numpoints); + + if (!prog_args.input_file_name) { + if (plot_track) { + srsran_npss_synch_t* pss_obj = &ue_sync.strack.npss; + int max = srsran_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size + pss_obj->fft_size - 1); + srsran_vec_sc_prod_fff(pss_obj->conv_output_avg, + 1 / pss_obj->conv_output_avg[max], + tmp_plot2, + pss_obj->frame_size + pss_obj->fft_size - 1); + plot_real_setNewData(&p_sync, &tmp_plot2[max - NPSS_FIND_PLOT_WIDTH / 2], NPSS_FIND_PLOT_WIDTH); + } else { + int len = SRSRAN_NPSS_CORR_FILTER_LEN + ue_sync.sfind.npss.frame_size - 1; + int max = srsran_vec_max_fi(ue_sync.sfind.npss.conv_output_avg, len); + srsran_vec_sc_prod_fff( + ue_sync.sfind.npss.conv_output_avg, 1 / ue_sync.sfind.npss.conv_output_avg[max], tmp_plot2, len); + plot_real_setNewData(&p_sync, tmp_plot2, len); + } + } + +#if HAVE_RSRP_PLOT + // get current RSRP estimate + rsrp_lin = SRSRAN_VEC_EMA(srsran_chest_dl_nbiot_get_rsrp(&ue_dl.chest), rsrp_lin, 0.05); + rsrp_table[rsrp_table_index++] = 10 * log10(rsrp_lin); + if (rsrp_table_index == rsrp_num_plot) { + rsrp_table_index = 0; + } + plot_real_setNewData(&rsrp_plot, rsrp_table, rsrp_num_plot); +#endif + + // update MIB and SIB widget only if their content changed + if (memcmp(mib_buffer_disp, mib_buffer_decode, sizeof(mib_buffer_disp)) != 0) { + memcpy(mib_buffer_disp, mib_buffer_decode, sizeof(mib_buffer_disp)); + text_edit_setMessage(&miblog, mib_buffer_disp); + } + if (memcmp(sib1_buffer_disp, sib1_buffer_decode, sizeof(sib1_buffer_disp)) != 0) { + memcpy(sib1_buffer_disp, sib1_buffer_decode, sizeof(sib1_buffer_disp)); + text_edit_setMessage(&sib1log, sib1_buffer_disp); + } + if (memcmp(sib2_buffer_disp, sib2_buffer_decode, sizeof(sib2_buffer_disp)) != 0) { + memcpy(sib2_buffer_disp, sib2_buffer_decode, sizeof(sib2_buffer_disp)); + text_edit_setMessage(&sib2log, sib2_buffer_disp); + } + + snprintf(lable_buf, LABLE_MAX_LEN, "%d", cell.n_id_ncell); + key_value_setValueText(&id_label, lable_buf); + + key_value_setValueText(&mode_label, srsran_nbiot_mode_string(cell.mode)); + + snprintf(lable_buf, LABLE_MAX_LEN, "%d / %d", hyper_frame_number, system_frame_number); + key_value_setValueText(&hfn_label, lable_buf); + } + + // check if NPDSCH or NPDCCH has been received + if (ue_dl.npdsch_cfg.nbits.nof_re) { + // plot NPDSCH + plot_scatter_setNewData(&constellation_plot, ue_dl.npdsch.d, ue_dl.npdsch_cfg.nbits.nof_re); + + } else if (ue_dl.npdcch.num_decoded_symbols) { + // plot NPDCCH + plot_scatter_setNewData(&constellation_plot, ue_dl.npdcch.d, ue_dl.npdcch.num_decoded_symbols); + } + } + + return NULL; +} + +void init_plots() +{ + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, NULL, plot_thread_run, NULL)) { + perror("pthread_create"); + exit(-1); + } +} + +#endif // ENABLE_GUI diff --git a/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.cc b/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.cc new file mode 100644 index 0000000..24121bc --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.cc @@ -0,0 +1,101 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "npdsch_ue_helper.h" +#include "srsran/asn1/rrc_nbiot.h" +#include "srsran/phy/utils/vector.h" // for SRSRAN_MIN + +int get_sib2_params(const uint8_t* sib1_payload, const uint32_t len, srsran_nbiot_si_params_t* sib2_params) +{ + memset(sib2_params, 0, sizeof(srsran_nbiot_si_params_t)); + + // unpack SIB + asn1::rrc::bcch_dl_sch_msg_nb_s dlsch_msg; + asn1::cbit_ref dlsch_bref(sib1_payload, len); + asn1::SRSASN_CODE err = dlsch_msg.unpack(dlsch_bref); + if (err != asn1::SRSASN_SUCCESS) { + fprintf(stderr, "Error unpacking DL-SCH message\n"); + return SRSRAN_ERROR; + } + + // set SIB2-NB parameters + sib2_params->n = 1; + auto sched_info = dlsch_msg.msg.c1().sib_type1_r13().sched_info_list_r13.begin(); + sib2_params->si_periodicity = sched_info->si_periodicity_r13.to_number(); + if (dlsch_msg.msg.c1().sib_type1_r13().si_radio_frame_offset_r13_present) { + sib2_params->si_radio_frame_offset = dlsch_msg.msg.c1().sib_type1_r13().si_radio_frame_offset_r13; + } + sib2_params->si_repetition_pattern = sched_info->si_repeat_pattern_r13.to_number(); + sib2_params->si_tb = sched_info->si_tb_r13.to_number(); + sib2_params->si_window_length = dlsch_msg.msg.c1().sib_type1_r13().si_win_len_r13.to_number(); + + return SRSRAN_SUCCESS; +} + +/* + * Unpacks BCCH BCH message and writes JSON formatted message to output + */ +int bcch_bch_to_pretty_string(const uint8_t* bcch_bch_payload, + const uint32_t input_len, + char* output, + const uint32_t max_output_len) +{ + asn1::rrc::bcch_bch_msg_nb_s bch_msg; + asn1::cbit_ref bch_bref(bcch_bch_payload, input_len); + asn1::SRSASN_CODE err = bch_msg.unpack(bch_bref); + if (err != asn1::SRSASN_SUCCESS) { + fprintf(stderr, "Error unpacking BCCH message\n"); + return SRSRAN_ERROR; + } + + asn1::json_writer json_writer; + bch_msg.to_json(json_writer); + + uint32_t output_len = SRSRAN_MIN(max_output_len, json_writer.to_string().length()); + memcpy(output, json_writer.to_string().c_str(), output_len); + + return SRSRAN_SUCCESS; +} + +/* + * Unpacks BCCH DL-SCH message and writes JSON formatted message to output + */ +int bcch_dl_sch_to_pretty_string(const uint8_t* bcch_dl_sch_payload, + const uint32_t input_len, + char* output, + const uint32_t max_output_len) +{ + asn1::rrc::bcch_dl_sch_msg_nb_s dlsch_msg; + asn1::cbit_ref dlsch_bref(bcch_dl_sch_payload, input_len); + asn1::SRSASN_CODE err = dlsch_msg.unpack(dlsch_bref); + if (err != asn1::SRSASN_SUCCESS) { + fprintf(stderr, "Error unpacking DL-SCH message\n"); + return SRSRAN_ERROR; + } + + asn1::json_writer json_writer; + dlsch_msg.to_json(json_writer); + + uint32_t output_len = SRSRAN_MIN(max_output_len, json_writer.to_string().length()); + memcpy(output, json_writer.to_string().c_str(), output_len); + + return SRSRAN_SUCCESS; +} \ No newline at end of file diff --git a/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.h b/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.h new file mode 100644 index 0000000..26b6d72 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/npdsch_ue_helper.h @@ -0,0 +1,46 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_NPDSCH_UE_HELPER_H +#define SRSRAN_NPDSCH_UE_HELPER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "srsran/phy/phch/ra_nbiot.h" +#include + +int get_sib2_params(const uint8_t* sib1_payload, const uint32_t len, srsran_nbiot_si_params_t* sib2_params); +int bcch_bch_to_pretty_string(const uint8_t* bcch_bch_payload, + const uint32_t input_len, + char* output, + const uint32_t max_output_len); +int bcch_dl_sch_to_pretty_string(const uint8_t* bcch_dl_sch_payload, + const uint32_t input_len, + char* output, + const uint32_t max_output_len); + +#ifdef __cplusplus +} +#endif + +#endif // SRSRAN_NPDSCH_UE_HELPER_H diff --git a/srsRAN_4G_mirror/lib/examples/pdsch_enodeb.c b/srsRAN_4G_mirror/lib/examples/pdsch_enodeb.c new file mode 100644 index 0000000..4425130 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/pdsch_enodeb.c @@ -0,0 +1,1032 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsran/common/crash_handler.h" +#include "srsran/common/gen_mch_tables.h" +#include "srsran/srsran.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UE_CRNTI 0x1234 +#define M_CRNTI 0xFFFD + +#ifndef DISABLE_RF +#include "srsran/phy/common/phy_common.h" +#include "srsran/phy/rf/rf.h" +srsran_rf_t radio; +#else +#pragma message "Compiling pdsch_ue with no RF support" +#endif + +static char* output_file_name = NULL; + +#define LEFT_KEY 68 +#define RIGHT_KEY 67 +#define UP_KEY 65 +#define DOWN_KEY 66 +#define PAGE_UP 53 +#define PAGE_DOWN 54 + +static srsran_cell_t cell = { + 25, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSRAN_CP_NORM, // cyclic prefix + SRSRAN_PHICH_NORM, // PHICH length + SRSRAN_PHICH_R_1, // PHICH resources + SRSRAN_FDD, +}; + +static int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device +static uint32_t cfi = 2; +static uint32_t mcs_idx = 1, last_mcs_idx = 1; +static int nof_frames = -1; +static srsran_tm_t transmission_mode = SRSRAN_TM1; +static uint32_t nof_tb = 1; +static uint32_t multiplex_pmi = 0; +static uint32_t multiplex_nof_layers = 1; +static uint8_t mbsfn_sf_mask = 32; +static int mbsfn_area_id = -1; +static char* rf_args = ""; +static char* rf_dev = ""; +static float rf_amp = 0.8, rf_gain = 60.0, rf_freq = 2400000000; +static bool enable_256qam = false; +static float output_file_snr = +INFINITY; +static bool use_standard_lte_rate = false; + +static bool null_file_sink = false; +static srsran_filesink_t fsink; +static srsran_ofdm_t ifft[SRSRAN_MAX_PORTS]; +static srsran_ofdm_t ifft_mbsfn; +static srsran_pbch_t pbch; +static srsran_pcfich_t pcfich; +static srsran_pdcch_t pdcch; +static srsran_pdsch_t pdsch; +static srsran_pdsch_cfg_t pdsch_cfg; +static srsran_pmch_t pmch; +static srsran_pmch_cfg_t pmch_cfg; +static srsran_softbuffer_tx_t* softbuffers[SRSRAN_MAX_CODEWORDS]; +static srsran_regs_t regs; +static srsran_dci_dl_t dci_dl; +static int rvidx[SRSRAN_MAX_CODEWORDS] = {0, 0}; + +static cf_t * sf_buffer[SRSRAN_MAX_PORTS] = {NULL}, *output_buffer[SRSRAN_MAX_PORTS] = {NULL}; +static uint32_t sf_n_re, sf_n_samples; + +static pthread_t net_thread; +static void* net_thread_fnc(void* arg); +static sem_t net_sem; +static bool net_packet_ready = false; +static srsran_netsource_t net_source; +static srsran_netsink_t net_sink; + +static int prbset_num = 1, last_prbset_num = 1; +static int prbset_orig = 0; +//#define DATA_BUFF_SZ 1024*128 +// uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ]; +// uint8_t data_tmp[DATA_BUFF_SZ]; + +#define DATA_BUFF_SZ 1024 * 1024 +static uint8_t *data_mbms, *data[2], data2[DATA_BUFF_SZ]; +static uint8_t data_tmp[DATA_BUFF_SZ]; + +static void usage(char* prog) +{ + printf("Usage: %s [Iagmfoncvpuxb]\n", prog); +#ifndef DISABLE_RF + printf("\t-I RF device [Default %s]\n", rf_dev); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); + printf("\t-g RF TX gain [Default %.2f dB]\n", rf_gain); + printf("\t-f RF TX frequency [Default %.1f MHz]\n", rf_freq / 1000000); +#else + printf("\t RF is disabled.\n"); +#endif + printf("\t-o output_file [Default use RF board]\n"); + printf("\t-m MCS index [Default %d]\n", mcs_idx); + printf("\t-n number of frames [Default %d]\n", nof_frames); + printf("\t-c cell id [Default %d]\n", cell.id); + printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-M MBSFN area id [Default %d]\n", mbsfn_area_id); + printf("\t-x Transmission mode [1-4] [Default %d]\n", transmission_mode + 1); + printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi); + printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); + printf("\t-u listen TCP/UDP port for input data (if mbsfn is active then the stream is over mbsfn only) (-1 is " + "random) [Default %d]\n", + net_port); + printf("\t-v [set srsran_verbose to debug, default none]\n"); + printf("\t-s output file SNR [Default %f]\n", output_file_snr); + printf("\t-q Enable/Disable 256QAM modulation (default %s)\n", enable_256qam ? "enabled" : "disabled"); + printf("\t-Q Use standard LTE sample rates (default %s)\n", use_standard_lte_rate ? "enabled" : "disabled"); + printf("\n"); + printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n"); +} + +static void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "IadglfmoncpqvutxbwMsBQ")) != -1) { + switch (opt) { + case 'I': + rf_dev = argv[optind]; + break; + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'l': + rf_amp = strtof(argv[optind], NULL); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'o': + output_file_name = argv[optind]; + break; + case 'm': + mcs_idx = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'u': + net_port = (int)strtol(argv[optind], NULL, 10); + break; + case 'n': + nof_frames = (int)strtol(argv[optind], NULL, 10); + break; + case 'p': + cell.nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'c': + cell.id = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'x': + transmission_mode = (srsran_tm_t)(strtol(argv[optind], NULL, 10) - 1); + break; + case 'b': + multiplex_pmi = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'w': + multiplex_nof_layers = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'M': + mbsfn_area_id = (int)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + case 's': + output_file_snr = strtof(argv[optind], NULL); + break; + case 'B': + mbsfn_sf_mask = (uint8_t)strtol(argv[optind], NULL, 10); + break; + case 'q': + enable_256qam ^= true; + break; + case 'Q': + use_standard_lte_rate ^= true; + break; + case 'E': + cell.cp = SRSRAN_CP_EXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } +#ifdef DISABLE_RF + if (!output_file_name) { + usage(argv[0]); + exit(-1); + } +#endif +} + +static void base_init() +{ + int i; + + /* Configure cell and PDSCH in function of the transmission mode */ + switch (transmission_mode) { + case SRSRAN_TM1: + cell.nof_ports = 1; + break; + case SRSRAN_TM2: + case SRSRAN_TM3: + case SRSRAN_TM4: + cell.nof_ports = 2; + break; + default: + ERROR("Transmission mode %d not implemented or invalid", transmission_mode); + exit(-1); + } + + /* Allocate memory */ + for (i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + data[i] = srsran_vec_u8_malloc(SOFTBUFFER_SIZE); + if (!data[i]) { + perror("malloc"); + exit(-1); + } + bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE); + } + data_mbms = srsran_vec_u8_malloc(SOFTBUFFER_SIZE); + + /* init memory */ + for (i = 0; i < SRSRAN_MAX_PORTS; i++) { + sf_buffer[i] = srsran_vec_cf_malloc(sf_n_re); + if (!sf_buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + for (i = 0; i < SRSRAN_MAX_PORTS; i++) { + output_buffer[i] = srsran_vec_cf_malloc(sf_n_samples); + if (!output_buffer[i]) { + perror("malloc"); + exit(-1); + } + srsran_vec_cf_zero(output_buffer[i], sf_n_samples); + } + + /* open file or USRP */ + if (output_file_name) { + if (strcmp(output_file_name, "NULL")) { + if (srsran_filesink_init(&fsink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN)) { + ERROR("Error opening file %s", output_file_name); + exit(-1); + } + null_file_sink = false; + } else { + null_file_sink = true; + } + } else { +#ifndef DISABLE_RF + printf("Opening RF device...\n"); + if (srsran_rf_open_devname(&radio, rf_dev, rf_args, cell.nof_ports)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } +#else + printf("Error RF not available. Select an output file\n"); + exit(-1); +#endif + } + + if (net_port > 0) { + if (srsran_netsource_init(&net_source, "127.0.0.1", net_port, SRSRAN_NETSOURCE_UDP)) { + ERROR("Error creating input UDP socket at port %d", net_port); + exit(-1); + } + if (null_file_sink) { + if (srsran_netsink_init(&net_sink, "127.0.0.1", net_port + 1, SRSRAN_NETSINK_TCP)) { + ERROR("Error sink"); + exit(-1); + } + } + if (sem_init(&net_sem, 0, 1)) { + perror("sem_init"); + exit(-1); + } + } + + /* create ifft object */ + for (i = 0; i < cell.nof_ports; i++) { + if (srsran_ofdm_tx_init(&ifft[i], cell.cp, sf_buffer[i], output_buffer[i], cell.nof_prb)) { + ERROR("Error creating iFFT object"); + exit(-1); + } + + srsran_ofdm_set_normalize(&ifft[i], true); + } + + if (srsran_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSRAN_CP_EXT, sf_buffer[0], output_buffer[0], cell.nof_prb)) { + ERROR("Error creating iFFT object"); + exit(-1); + } + srsran_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); + srsran_ofdm_set_normalize(&ifft_mbsfn, true); + + if (srsran_pbch_init(&pbch)) { + ERROR("Error creating PBCH object"); + exit(-1); + } + if (srsran_pbch_set_cell(&pbch, cell)) { + ERROR("Error creating PBCH object"); + exit(-1); + } + + if (srsran_regs_init(®s, cell)) { + ERROR("Error initiating regs"); + exit(-1); + } + if (srsran_pcfich_init(&pcfich, 1)) { + ERROR("Error creating PBCH object"); + exit(-1); + } + if (srsran_pcfich_set_cell(&pcfich, ®s, cell)) { + ERROR("Error creating PBCH object"); + exit(-1); + } + + if (srsran_pdcch_init_enb(&pdcch, cell.nof_prb)) { + ERROR("Error creating PDCCH object"); + exit(-1); + } + if (srsran_pdcch_set_cell(&pdcch, ®s, cell)) { + ERROR("Error creating PDCCH object"); + exit(-1); + } + + if (srsran_pdsch_init_enb(&pdsch, cell.nof_prb)) { + ERROR("Error creating PDSCH object"); + exit(-1); + } + if (srsran_pdsch_set_cell(&pdsch, cell)) { + ERROR("Error creating PDSCH object"); + exit(-1); + } + + if (mbsfn_area_id > -1) { + if (srsran_pmch_init(&pmch, cell.nof_prb, 1)) { + ERROR("Error creating PMCH object"); + } + srsran_pmch_set_area_id(&pmch, mbsfn_area_id); + } + + for (i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + softbuffers[i] = calloc(sizeof(srsran_softbuffer_tx_t), 1); + if (!softbuffers[i]) { + ERROR("Error allocating soft buffer"); + exit(-1); + } + + if (srsran_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) { + ERROR("Error initiating soft buffer"); + exit(-1); + } + } +} + +static void base_free() +{ + int i; + for (i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + srsran_softbuffer_tx_free(softbuffers[i]); + if (softbuffers[i]) { + free(softbuffers[i]); + } + } + srsran_pdsch_free(&pdsch); + srsran_pdcch_free(&pdcch); + srsran_regs_free(®s); + srsran_pbch_free(&pbch); + if (mbsfn_area_id > -1) { + srsran_pmch_free(&pmch); + } + srsran_ofdm_tx_free(&ifft_mbsfn); + for (i = 0; i < cell.nof_ports; i++) { + srsran_ofdm_tx_free(&ifft[i]); + } + + for (i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + + for (i = 0; i < SRSRAN_MAX_PORTS; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + + if (output_buffer[i]) { + free(output_buffer[i]); + } + } + if (output_file_name) { + if (!null_file_sink) { + srsran_filesink_free(&fsink); + } + } else { +#ifndef DISABLE_RF + srsran_rf_close(&radio); +#endif + } + + if (net_port > 0) { + srsran_netsource_free(&net_source); + sem_close(&net_sem); + } +} + +bool go_exit = false; +#ifndef DISABLE_RF +static void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } +} +#endif /* DISABLE_RF */ + +static unsigned int reverse(register unsigned int x) +{ + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + return ((x >> 16) | (x << 16)); +} + +static uint32_t prbset_to_bitmask() +{ + uint32_t mask = 0; + int nb = (int)ceilf((float)cell.nof_prb / srsran_ra_type0_P(cell.nof_prb)); + for (int i = 0; i < nb; i++) { + if (i >= prbset_orig && i < prbset_orig + prbset_num) { + mask = mask | (0x1 << i); + } + } + return reverse(mask) >> (32 - nb); +} + +static int update_radl() +{ + ZERO_OBJECT(dci_dl); + + /* Configure cell and PDSCH in function of the transmission mode */ + switch (transmission_mode) { + case SRSRAN_TM1: + case SRSRAN_TM2: + nof_tb = 1; + dci_dl.format = SRSRAN_DCI_FORMAT1; + break; + case SRSRAN_TM3: + dci_dl.format = SRSRAN_DCI_FORMAT2A; + nof_tb = 2; + break; + case SRSRAN_TM4: + dci_dl.format = SRSRAN_DCI_FORMAT2; + nof_tb = multiplex_nof_layers; + if (multiplex_nof_layers == 1) { + dci_dl.pinfo = (uint8_t)(multiplex_pmi + 1); + } else { + dci_dl.pinfo = (uint8_t)multiplex_pmi; + } + break; + default: + ERROR("Transmission mode not implemented."); + exit(-1); + } + + dci_dl.rnti = UE_CRNTI; + dci_dl.pid = 0; + dci_dl.tb[0].mcs_idx = mcs_idx; + dci_dl.tb[0].ndi = 0; + dci_dl.tb[0].rv = rvidx[0]; + dci_dl.tb[0].cw_idx = 0; + dci_dl.alloc_type = SRSRAN_RA_ALLOC_TYPE0; + dci_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); + + if (nof_tb > 1) { + dci_dl.tb[1].mcs_idx = mcs_idx; + dci_dl.tb[1].ndi = 0; + dci_dl.tb[1].rv = rvidx[1]; + dci_dl.tb[1].cw_idx = 1; + } else { + SRSRAN_DCI_TB_DISABLE(dci_dl.tb[1]); + } + + srsran_dci_dl_fprint(stdout, &dci_dl, cell.nof_prb); + if (transmission_mode != SRSRAN_TM1) { + printf("\nTransmission mode key table:\n"); + printf(" Mode | 1TB | 2TB |\n"); + printf("----------+---------+-----+\n"); + printf("Diversity | x | |\n"); + printf(" CDD | | z |\n"); + printf("Multiplex | q,w,e,r | a,s |\n"); + printf("\n"); + printf("Type new MCS index (0-28) or mode key and press Enter: "); + } else { + printf("Type new MCS index (0-28) and press Enter: "); + } + fflush(stdout); + + return 0; +} + +/* Read new MCS from stdin */ +static int update_control() +{ + char input[128]; + + fd_set set; + FD_ZERO(&set); + FD_SET(0, &set); + + struct timeval to; + to.tv_sec = 0; + to.tv_usec = 0; + + int n = select(1, &set, NULL, NULL, &to); + if (n == 1) { + // stdin ready + if (fgets(input, sizeof(input), stdin)) { + if (input[0] == 27) { + switch (input[2]) { + case RIGHT_KEY: + if (prbset_orig + prbset_num < (int)ceilf((float)cell.nof_prb / srsran_ra_type0_P(cell.nof_prb))) + prbset_orig++; + break; + case LEFT_KEY: + if (prbset_orig > 0) + prbset_orig--; + break; + case UP_KEY: + if (prbset_num < (int)ceilf((float)cell.nof_prb / srsran_ra_type0_P(cell.nof_prb))) + prbset_num++; + break; + case DOWN_KEY: + last_prbset_num = prbset_num; + if (prbset_num > 0) + prbset_num--; + break; +#ifndef DISABLE_RF + case PAGE_UP: + if (!output_file_name) { + rf_gain++; + srsran_rf_set_tx_gain(&radio, rf_gain); + printf("Set TX gain: %.1f dB\n", srsran_rf_get_tx_gain(&radio)); + } + break; + case PAGE_DOWN: + if (!output_file_name) { + rf_gain--; + srsran_rf_set_tx_gain(&radio, rf_gain); + printf("Set TX gain: %.1f dB\n", srsran_rf_get_tx_gain(&radio)); + } + break; +#endif + } + } else { + switch (input[0]) { + case 'q': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 0; + multiplex_nof_layers = 1; + break; + case 'w': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 1; + multiplex_nof_layers = 1; + break; + case 'e': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 2; + multiplex_nof_layers = 1; + break; + case 'r': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 3; + multiplex_nof_layers = 1; + break; + case 'a': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 0; + multiplex_nof_layers = 2; + break; + case 's': + transmission_mode = SRSRAN_TM4; + multiplex_pmi = 1; + multiplex_nof_layers = 2; + break; + case 'z': + transmission_mode = SRSRAN_TM3; + break; + case 'x': + transmission_mode = SRSRAN_TM2; + break; + default: + last_mcs_idx = mcs_idx; + mcs_idx = strtol(input, NULL, 10); + } + } + bzero(input, sizeof(input)); + if (update_radl()) { + printf("Trying with last known MCS index\n"); + mcs_idx = last_mcs_idx; + prbset_num = last_prbset_num; + return update_radl(); + } + } + return 0; + } else if (n < 0) { + // error + perror("select"); + return -1; + } else { + return 0; + } +} + +/** Function run in a separate thread to receive UDP data */ +static void* net_thread_fnc(void* arg) +{ + int n; + int rpm = 0, wpm = 0; + + do { + n = srsran_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ - rpm); + if (n > 0) { + // TODO: I assume that both transport blocks have same size in case of 2 tb are active + + int nbytes = 1 + (((mbsfn_area_id > -1) ? (pmch_cfg.pdsch_cfg.grant.tb[0].tbs) + : (pdsch_cfg.grant.tb[0].tbs + pdsch_cfg.grant.tb[1].tbs)) - + 1) / + 8; + rpm += n; + INFO("received %d bytes. rpm=%d/%d", n, rpm, nbytes); + wpm = 0; + while (rpm >= nbytes) { + // wait for packet to be transmitted + sem_wait(&net_sem); + if (mbsfn_area_id > -1) { + memcpy(data_mbms, &data2[wpm], nbytes); + } else { + memcpy(data[0], &data2[wpm], nbytes / (size_t)2); + memcpy(data[1], &data2[wpm], nbytes / (size_t)2); + } + INFO("Sent %d/%d bytes ready", nbytes, rpm); + rpm -= nbytes; + wpm += nbytes; + net_packet_ready = true; + } + if (wpm > 0) { + INFO("%d bytes left in buffer for next packet", rpm); + memcpy(data2, &data2[wpm], rpm * sizeof(uint8_t)); + } + } else if (n == 0) { + rpm = 0; + } else { + ERROR("Error receiving from network"); + exit(-1); + } + } while (true); +} + +int main(int argc, char** argv) +{ + int nf = 0, sf_idx = 0, N_id_2 = 0; + cf_t pss_signal[SRSRAN_PSS_LEN]; + float sss_signal0[SRSRAN_SSS_LEN]; // for subframe 0 + float sss_signal5[SRSRAN_SSS_LEN]; // for subframe 5 + uint8_t bch_payload[SRSRAN_BCH_PAYLOAD_LEN]; + int i; + cf_t* sf_symbols[SRSRAN_MAX_PORTS]; + srsran_dci_msg_t dci_msg; + srsran_dci_location_t locations[SRSRAN_NOF_SF_X_FRAME][30]; + uint32_t sfn; + srsran_refsignal_t csr_refs; + srsran_refsignal_t mbsfn_refs; + + srsran_debug_handle_crash(argc, argv); + +#ifdef DISABLE_RF + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc, argv); + + srsran_use_standard_symbol_size(use_standard_lte_rate); + + uint8_t mch_table[10]; + bzero(&mch_table[0], sizeof(uint8_t) * 10); + if (mbsfn_area_id > -1) { + generate_mcch_table(mch_table, mbsfn_sf_mask); + } + N_id_2 = cell.id % 3; + sf_n_re = SRSRAN_SF_LEN_RE(cell.nof_prb, cell.cp); + sf_n_samples = 2 * SRSRAN_SLOT_LEN(srsran_symbol_sz(cell.nof_prb)); + + cell.phich_length = SRSRAN_PHICH_NORM; + cell.phich_resources = SRSRAN_PHICH_R_1; + sfn = 0; + + prbset_num = (int)ceilf((float)cell.nof_prb / srsran_ra_type0_P(cell.nof_prb)); + last_prbset_num = prbset_num; + + /* this *must* be called after setting slot_len_* */ + base_init(); + + /* Generate PSS/SSS signals */ + srsran_pss_generate(pss_signal, N_id_2); + srsran_sss_generate(sss_signal0, sss_signal5, cell.id); + + /* Generate reference signals */ + if (srsran_refsignal_cs_init(&csr_refs, cell.nof_prb)) { + ERROR("Error initializing equalizer"); + exit(-1); + } + if (mbsfn_area_id > -1) { + if (srsran_refsignal_mbsfn_init(&mbsfn_refs, cell.nof_prb)) { + ERROR("Error initializing equalizer"); + exit(-1); + } + if (srsran_refsignal_mbsfn_set_cell(&mbsfn_refs, cell, mbsfn_area_id)) { + ERROR("Error initializing MBSFNR signal"); + exit(-1); + } + } + + if (srsran_refsignal_cs_set_cell(&csr_refs, cell)) { + ERROR("Error setting cell"); + exit(-1); + } + + for (i = 0; i < SRSRAN_MAX_PORTS; i++) { + sf_symbols[i] = sf_buffer[i % cell.nof_ports]; + } + +#ifndef DISABLE_RF + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + if (!output_file_name) { + int srate = srsran_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + float srate_rf = srsran_rf_set_tx_srate(&radio, (double)srate); + if (srate_rf != srate) { + ERROR("Could not set sampling rate"); + exit(-1); + } + } else { + ERROR("Invalid number of PRB %d", cell.nof_prb); + exit(-1); + } + srsran_rf_set_tx_gain(&radio, rf_gain); + printf("Set TX gain: %.1f dB\n", srsran_rf_get_tx_gain(&radio)); + printf("Set TX freq: %.2f MHz\n", srsran_rf_set_tx_freq(&radio, cell.nof_ports, rf_freq) / 1000000); + } +#endif + + if (update_radl()) { + exit(-1); + } + + if (net_port > 0) { + if (pthread_create(&net_thread, NULL, net_thread_fnc, NULL)) { + perror("pthread_create"); + exit(-1); + } + } + pmch_cfg.pdsch_cfg.grant.tb[0].tbs = 1096; + + srsran_dl_sf_cfg_t dl_sf; + ZERO_OBJECT(dl_sf); + + /* Initiate valid DCI locations */ + for (i = 0; i < SRSRAN_NOF_SF_X_FRAME; i++) { + dl_sf.cfi = cfi; + dl_sf.tti = i; + srsran_pdcch_ue_locations(&pdcch, &dl_sf, locations[i], 30, UE_CRNTI); + } + + nf = 0; + + bool send_data = false; + for (i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + srsran_softbuffer_tx_reset(softbuffers[i]); + } + +#ifndef DISABLE_RF + bool start_of_burst = true; +#endif + + ZERO_OBJECT(pdsch_cfg); + for (uint32_t j = 0; j < SRSRAN_MAX_CODEWORDS; j++) { + pdsch_cfg.softbuffers.tx[j] = softbuffers[j]; + } + pdsch_cfg.rnti = UE_CRNTI; + + pmch_cfg.pdsch_cfg = pdsch_cfg; + + while ((nf < nof_frames || nof_frames == -1) && !go_exit) { + for (sf_idx = 0; sf_idx < SRSRAN_NOF_SF_X_FRAME && (nf < nof_frames || nof_frames == -1) && !go_exit; sf_idx++) { + /* Set Antenna port resource elements to zero */ + srsran_vec_cf_zero(sf_symbols[0], sf_n_re); + + if (sf_idx == 0 || sf_idx == 5) { + srsran_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, cell.cp); + srsran_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb, cell.cp); + } + + /* Copy zeros, SSS, PSS into the rest of antenna ports */ + for (i = 1; i < cell.nof_ports; i++) { + memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re); + } + + if (mch_table[sf_idx] == 1 && mbsfn_area_id > -1) { + srsran_refsignal_mbsfn_put_sf(cell, 0, csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]); + } else { + dl_sf.tti = nf * 10 + sf_idx; + for (i = 0; i < cell.nof_ports; i++) { + srsran_refsignal_cs_put_sf(&csr_refs, &dl_sf, (uint32_t)i, sf_symbols[i]); + } + } + + srsran_pbch_mib_pack(&cell, sfn, bch_payload); + if (sf_idx == 0) { + srsran_pbch_encode(&pbch, bch_payload, sf_symbols, nf % 4); + } + + dl_sf.tti = nf * 10 + sf_idx; + dl_sf.cfi = cfi; + + srsran_pcfich_encode(&pcfich, &dl_sf, sf_symbols); + + /* Update DL resource allocation from control port */ + if (update_control()) { + ERROR("Error updating parameters from control port"); + } + + /* Transmit PDCCH + PDSCH only when there is data to send */ + if ((net_port > 0) && (mch_table[sf_idx] == 1 && mbsfn_area_id > -1)) { + send_data = net_packet_ready; + if (net_packet_ready) { + INFO("Transmitting packet from port"); + } + } else { + INFO("SF: %d, Generating %d random bits", sf_idx, pdsch_cfg.grant.tb[0].tbs + pdsch_cfg.grant.tb[1].tbs); + for (uint32_t tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { + if (pdsch_cfg.grant.tb[tb].enabled) { + for (i = 0; i < pdsch_cfg.grant.tb[tb].tbs / 8; i++) { + data[tb][i] = (uint8_t)rand(); + } + } + } + /* Uncomment this to transmit on sf 0 and 5 only */ + if (sf_idx != 0 && sf_idx != 5) { + send_data = true; + } else { + send_data = false; + } + } + if (send_data) { + if (mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { // PDCCH + PDSCH + dl_sf.sf_type = SRSRAN_SF_NORM; + + /* Encode PDCCH */ + INFO("Putting DCI to location: n=%d, L=%d", locations[sf_idx][0].ncce, locations[sf_idx][0].L); + + srsran_dci_msg_pack_pdsch(&cell, &dl_sf, NULL, &dci_dl, &dci_msg); + dci_msg.location = locations[sf_idx][0]; + if (srsran_pdcch_encode(&pdcch, &dl_sf, &dci_msg, sf_symbols)) { + ERROR("Error encoding DCI message"); + exit(-1); + } + + /* Configure pdsch_cfg parameters */ + if (srsran_ra_dl_dci_to_grant(&cell, &dl_sf, transmission_mode, enable_256qam, &dci_dl, &pdsch_cfg.grant)) { + ERROR("Error configuring PDSCH"); + exit(-1); + } + + /* Encode PDSCH */ + if (srsran_pdsch_encode(&pdsch, &dl_sf, &pdsch_cfg, data, sf_symbols)) { + ERROR("Error encoding PDSCH"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + for (uint32_t tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { + srsran_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.tb[tb].tbs); + if (srsran_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.tb[tb].tbs - 1) / 8) < 0) { + ERROR("Error sending data through UDP socket"); + } + } + } + if (mbsfn_area_id < 0) { + net_packet_ready = false; + sem_post(&net_sem); + } + } + } else { // We're sending MCH on subframe 1 - PDCCH + PMCH + dl_sf.sf_type = SRSRAN_SF_MBSFN; + + /* Force 1 word and MCS 2 */ + dci_dl.rnti = SRSRAN_MRNTI; + dci_dl.alloc_type = SRSRAN_RA_ALLOC_TYPE0; + dci_dl.type0_alloc.rbg_bitmask = 0xffffffff; + dci_dl.tb[0].mcs_idx = 2; + dci_dl.format = SRSRAN_DCI_FORMAT1; + + /* Configure pdsch_cfg parameters */ + if (srsran_ra_dl_dci_to_grant(&cell, &dl_sf, SRSRAN_TM1, enable_256qam, &dci_dl, &pmch_cfg.pdsch_cfg.grant)) { + ERROR("Error configuring PDSCH"); + exit(-1); + } + + for (int j = 0; j < pmch_cfg.pdsch_cfg.grant.tb[0].tbs / 8; j++) { + data_mbms[j] = j % 255; + } + + pmch_cfg.area_id = mbsfn_area_id; + + /* Encode PMCH */ + if (srsran_pmch_encode(&pmch, &dl_sf, &pmch_cfg, data_mbms, sf_symbols)) { + ERROR("Error encoding PDSCH"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + srsran_bit_pack_vector(data[0], data_tmp, pmch_cfg.pdsch_cfg.grant.tb[0].tbs); + if (srsran_netsink_write(&net_sink, data_tmp, 1 + (pmch_cfg.pdsch_cfg.grant.tb[0].tbs - 1) / 8) < 0) { + ERROR("Error sending data through UDP socket"); + } + } + net_packet_ready = false; + sem_post(&net_sem); + } + } + } + + /* Transform to OFDM symbols */ + if (mch_table[sf_idx] == 0 || mbsfn_area_id < 0) { + for (i = 0; i < cell.nof_ports; i++) { + srsran_ofdm_tx_sf(&ifft[i]); + } + } else { + srsran_ofdm_tx_sf(&ifft_mbsfn); + } + + /* send to file or usrp */ + if (output_file_name) { + if (!null_file_sink) { + /* Apply AWGN */ + if (output_file_snr != +INFINITY) { + float var = srsran_convert_dB_to_amplitude(-(output_file_snr + 3.0f)); + for (int k = 0; k < cell.nof_ports; k++) { + srsran_ch_awgn_c(output_buffer[k], output_buffer[k], var, sf_n_samples); + } + } + srsran_filesink_write_multi(&fsink, (void**)output_buffer, sf_n_samples, cell.nof_ports); + } + usleep(1000); + } else { +#ifndef DISABLE_RF + float norm_factor = (float)cell.nof_prb / 15 / sqrtf(pdsch_cfg.grant.nof_prb); + for (i = 0; i < cell.nof_ports; i++) { + srsran_vec_sc_prod_cfc( + output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSRAN_SF_LEN_PRB(cell.nof_prb)); + } + srsran_rf_send_multi(&radio, (void**)output_buffer, sf_n_samples, true, start_of_burst, false); + start_of_burst = false; +#endif + } + } + nf++; + sfn = (sfn + 1) % 1024; + } + + base_free(); + + printf("Done\n"); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/pdsch_ue.c b/srsRAN_4G_mirror/lib/examples/pdsch_ue.c new file mode 100644 index 0000000..03d26c8 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/pdsch_ue.c @@ -0,0 +1,1155 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/common/crash_handler.h" +#include "srsran/common/gen_mch_tables.h" +#include "srsran/phy/io/filesink.h" +#include "srsran/srsran.h" + +#define ENABLE_AGC_DEFAULT + +#ifndef DISABLE_RF + +#include "srsran/phy/rf/rf.h" +#include "srsran/phy/rf/rf_utils.h" + +cell_search_cfg_t cell_detect_config = {.max_frames_pbch = SRSRAN_DEFAULT_MAX_FRAMES_PBCH, + .max_frames_pss = SRSRAN_DEFAULT_MAX_FRAMES_PSS, + .nof_valid_pss_frames = SRSRAN_DEFAULT_NOF_VALID_PSS_FRAMES, + .init_agc = 0, + .force_tdd = false}; + +#else +#pragma message "Compiling pdsch_ue with no RF support" +#endif + +//#define STDOUT_COMPACT + +#ifdef ENABLE_GUI + +#include "srsgui/srsgui.h" + +void init_plots(); + +pthread_t plot_thread; +sem_t plot_sem; +uint32_t plot_sf_idx = 0; +bool plot_track = true; +bool enable_mbsfn_plot = false; +#endif /* ENABLE_GUI */ +char* output_file_name; +//#define PRINT_CHANGE_SCHEDULING + +//#define CORRECT_SAMPLE_OFFSET + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + int nof_subframes; + int cpu_affinity; + bool disable_plots; + bool disable_plots_except_constellation; + bool disable_cfo; + uint32_t time_offset; + int force_N_id_2; + uint16_t rnti; + char* input_file_name; + int file_offset_time; + float file_offset_freq; + uint32_t file_nof_prb; + uint32_t file_nof_ports; + uint32_t file_cell_id; + bool enable_cfo_ref; + char* estimator_alg; + char* rf_dev; + char* rf_args; + uint32_t rf_nof_rx_ant; + double rf_freq; + float rf_gain; + int net_port; + char* net_address; + int net_port_signal; + char* net_address_signal; + int decimate; + int32_t mbsfn_area_id; + uint8_t non_mbsfn_region; + uint8_t mbsfn_sf_mask; + int tdd_special_sf; + int sf_config; + int verbose; + bool enable_256qam; + bool use_standard_lte_rate; +} prog_args_t; + +void args_default(prog_args_t* args) +{ + args->disable_plots = false; + args->disable_plots_except_constellation = false; + args->nof_subframes = -1; + args->rnti = SRSRAN_SIRNTI; + args->force_N_id_2 = -1; // Pick the best + args->tdd_special_sf = -1; + args->sf_config = -1; + args->input_file_name = NULL; + args->disable_cfo = false; + args->time_offset = 0; + args->file_nof_prb = 25; + args->file_nof_ports = 1; + args->file_cell_id = 0; + args->file_offset_time = 0; + args->file_offset_freq = 0; + args->rf_dev = ""; + args->rf_args = ""; + args->rf_freq = -1.0; + args->rf_nof_rx_ant = 1; + args->enable_cfo_ref = false; + args->estimator_alg = "interpolate"; + args->enable_256qam = false; +#ifdef ENABLE_AGC_DEFAULT + args->rf_gain = -1.0; +#else + args->rf_gain = 50.0; +#endif + args->net_port = -1; + args->net_address = "127.0.0.1"; + args->net_port_signal = -1; + args->net_address_signal = "127.0.0.1"; + args->decimate = 0; + args->cpu_affinity = -1; + args->mbsfn_area_id = -1; + args->non_mbsfn_region = 2; + args->mbsfn_sf_mask = 32; +} + +void usage(prog_args_t* args, char* prog) +{ + printf("Usage: %s [adgpPoOcildFRDnruMNvTG] -f rx_frequency (in Hz) | -i input_file\n", prog); +#ifndef DISABLE_RF + printf("\t-I RF dev [Default %s]\n", args->rf_dev); + printf("\t-a RF args [Default %s]\n", args->rf_args); + printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); +#ifdef ENABLE_AGC_DEFAULT + printf("\t-g RF fix RX gain [Default AGC]\n"); +#else + printf("\t-g Set RX gain [Default %.1f dB]\n", args->rf_gain); +#endif +#else + printf("\t RF is disabled.\n"); +#endif + printf("\t-i input_file [Default use RF board]\n"); + printf("\t-o offset frequency correction (in Hz) for input file [Default %.1f Hz]\n", args->file_offset_freq); + printf("\t-O offset samples for input file [Default %d]\n", args->file_offset_time); + printf("\t-p nof_prb for input file [Default %d]\n", args->file_nof_prb); + printf("\t-P nof_ports for input file [Default %d]\n", args->file_nof_ports); + printf("\t-c cell_id for input file [Default %d]\n", args->file_cell_id); + printf("\t-r RNTI in Hex [Default 0x%x]\n", args->rnti); + printf("\t-l Force N_id_2 [Default best]\n"); + printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo ? "Disabled" : "Enabled"); + printf("\t-F Enable RS-based CFO correction [Default %s]\n", !args->enable_cfo_ref ? "Disabled" : "Enabled"); + printf("\t-R Channel estimates algorithm (average, interpolate, wiener) [Default %s]\n", args->estimator_alg); + printf("\t-t Add time offset [Default %d]\n", args->time_offset); + printf("\t-T Set TDD special subframe configuration [Default %d]\n", args->tdd_special_sf); + printf("\t-G Set TDD uplink/downlink configuration [Default %d]\n", args->sf_config); +#ifdef ENABLE_GUI + printf("\t-d disable plots [Default enabled]\n"); + printf("\t-D disable all but constellation plots [Default enabled]\n"); +#else /* ENABLE_GUI */ + printf("\t plots are disabled. Graphics library not available\n"); +#endif /* ENABLE_GUI */ + printf("\t-y set the cpu affinity mask [Default %d] \n ", args->cpu_affinity); + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-s remote UDP port to send input signal (-1 does nothing with it) [Default %d]\n", args->net_port_signal); + printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); + printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port); + printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address); + printf("\t-M MBSFN area id [Default %d]\n", args->mbsfn_area_id); + printf("\t-N Non-MBSFN region [Default %d]\n", args->non_mbsfn_region); + printf("\t-q Enable/Disable 256QAM modulation (default %s)\n", args->enable_256qam ? "enabled" : "disabled"); + printf("\t-Q Use standard LTE sample rates (default %s)\n", args->use_standard_lte_rate ? "enabled" : "disabled"); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +void parse_args(prog_args_t* args, int argc, char** argv) +{ + int opt; + args_default(args); + + while ((opt = getopt(argc, argv, "adAogliIpPcOCtdDFRqnvrfuUsSZyWMNBTGQ")) != -1) { + switch (opt) { + case 'i': + args->input_file_name = argv[optind]; + break; + case 'p': + args->file_nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'P': + args->file_nof_ports = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'o': + args->file_offset_freq = strtof(argv[optind], NULL); + break; + case 'O': + args->file_offset_time = (int)strtol(argv[optind], NULL, 10); + break; + case 'c': + args->file_cell_id = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'I': + args->rf_dev = argv[optind]; + break; + case 'a': + args->rf_args = argv[optind]; + break; + case 'A': + args->rf_nof_rx_ant = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'g': + args->rf_gain = strtof(argv[optind], NULL); + break; + case 'C': + args->disable_cfo = true; + break; + case 'F': + args->enable_cfo_ref = true; + break; + case 'R': + args->estimator_alg = argv[optind]; + break; + case 't': + args->time_offset = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'f': + args->rf_freq = strtod(argv[optind], NULL); + break; + case 'T': + args->tdd_special_sf = (int)strtol(argv[optind], NULL, 10); + break; + case 'G': + args->sf_config = (int)strtol(argv[optind], NULL, 10); + break; + case 'n': + args->nof_subframes = (int)strtol(argv[optind], NULL, 10); + break; + case 'r': + args->rnti = strtol(argv[optind], NULL, 16); + break; + case 'l': + args->force_N_id_2 = (int)strtol(argv[optind], NULL, 10); + break; + case 'u': + args->net_port = (int)strtol(argv[optind], NULL, 10); + break; + case 'U': + args->net_address = argv[optind]; + break; + case 's': + args->net_port_signal = (int)strtol(argv[optind], NULL, 10); + break; + case 'S': + args->net_address_signal = argv[optind]; + break; + case 'd': + args->disable_plots = true; + break; + case 'D': + args->disable_plots_except_constellation = true; + break; + case 'v': + increase_srsran_verbose_level(); + args->verbose = get_srsran_verbose_level(); + break; + case 'Z': + args->decimate = (int)strtol(argv[optind], NULL, 10); + break; + case 'y': + args->cpu_affinity = (int)strtol(argv[optind], NULL, 10); + break; + case 'W': + output_file_name = argv[optind]; + break; + case 'M': + args->mbsfn_area_id = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'N': + args->non_mbsfn_region = (uint8_t)strtol(argv[optind], NULL, 10); + break; + case 'B': + args->mbsfn_sf_mask = (uint8_t)strtol(argv[optind], NULL, 10); + break; + case 'q': + args->enable_256qam ^= true; + break; + case 'Q': + args->use_standard_lte_rate ^= true; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_freq < 0 && args->input_file_name == NULL) { + usage(args, argv[0]); + exit(-1); + } +} + +/**********************************************************************/ + +uint8_t* data[SRSRAN_MAX_CODEWORDS]; + +bool go_exit = false; + +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + go_exit = true; + } else if (signo == SIGSEGV) { + exit(1); + } +} + +cf_t* sf_buffer[SRSRAN_MAX_PORTS] = {NULL}; + +#ifndef DISABLE_RF + +int srsran_rf_recv_wrapper(void* h, cf_t* data_[SRSRAN_MAX_PORTS], uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + void* ptr[SRSRAN_MAX_PORTS]; + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + ptr[i] = data_[i]; + } + return srsran_rf_recv_with_time_multi(h, ptr, nsamples, true, NULL, NULL); +} + +static SRSRAN_AGC_CALLBACK(srsran_rf_set_rx_gain_th_wrapper_) +{ + srsran_rf_set_rx_gain_th((srsran_rf_t*)h, gain_db); +} + +#endif + +extern float mean_exec_time; + +enum receiver_state { DECODE_MIB, DECODE_PDSCH } state; + +srsran_cell_t cell; +srsran_ue_dl_t ue_dl; +srsran_ue_dl_cfg_t ue_dl_cfg; +srsran_dl_sf_cfg_t dl_sf; +srsran_pdsch_cfg_t pdsch_cfg; +srsran_ue_sync_t ue_sync; +prog_args_t prog_args; + +uint32_t pkt_errors = 0, pkt_total = 0, nof_detected = 0, pmch_pkt_errors = 0, pmch_pkt_total = 0, nof_trials = 0; + +srsran_netsink_t net_sink, net_sink_signal; +/* Useful macros for printing lines which will disappear */ + +#define PRINT_LINE_INIT() \ + int this_nof_lines = 0; \ + static int prev_nof_lines = 0 +#define PRINT_LINE(_fmt, ...) \ + printf("\033[K" _fmt "\n", ##__VA_ARGS__); \ + this_nof_lines++ +#define PRINT_LINE_RESET_CURSOR() \ + printf("\033[%dA", this_nof_lines); \ + prev_nof_lines = this_nof_lines +#define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1) + +int main(int argc, char** argv) +{ + int ret; + +#ifndef DISABLE_RF + srsran_rf_t rf; +#endif + + srsran_debug_handle_crash(argc, argv); + + parse_args(&prog_args, argc, argv); + + srsran_use_standard_symbol_size(prog_args.use_standard_lte_rate); + +#ifdef ENABLE_GUI + if (prog_args.mbsfn_area_id > -1) { + enable_mbsfn_plot = true; + } +#endif /* ENABLE_GUI */ + + for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + data[i] = srsran_vec_u8_malloc(2000 * 8); + if (!data[i]) { + ERROR("Allocating data"); + go_exit = true; + } + } + + uint8_t mch_table[10]; + bzero(&mch_table[0], sizeof(uint8_t) * 10); + if (prog_args.mbsfn_area_id > -1) { + generate_mcch_table(mch_table, prog_args.mbsfn_sf_mask); + } + if (prog_args.cpu_affinity > -1) { + cpu_set_t cpuset; + pthread_t thread; + + thread = pthread_self(); + for (int i = 0; i < 8; i++) { + if (((prog_args.cpu_affinity >> i) & 0x01) == 1) { + printf("Setting pdsch_ue with affinity to core %d\n", i); + CPU_SET((size_t)i, &cpuset); + } + if (pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset)) { + ERROR("Error setting main thread affinity to %d", prog_args.cpu_affinity); + exit(-1); + } + } + } + + if (prog_args.net_port > 0) { + if (srsran_netsink_init(&net_sink, prog_args.net_address, prog_args.net_port, SRSRAN_NETSINK_UDP)) { + ERROR("Error initiating UDP socket to %s:%d", prog_args.net_address, prog_args.net_port); + exit(-1); + } + srsran_netsink_set_nonblocking(&net_sink); + } + if (prog_args.net_port_signal > 0) { + if (srsran_netsink_init( + &net_sink_signal, prog_args.net_address_signal, prog_args.net_port_signal, SRSRAN_NETSINK_UDP)) { + ERROR("Error initiating UDP socket to %s:%d", prog_args.net_address_signal, prog_args.net_port_signal); + exit(-1); + } + srsran_netsink_set_nonblocking(&net_sink_signal); + } + + float search_cell_cfo = 0; + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + printf("Opening RF device with %d RX antennas...\n", prog_args.rf_nof_rx_ant); + if (srsran_rf_open_devname(&rf, prog_args.rf_dev, prog_args.rf_args, prog_args.rf_nof_rx_ant)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + /* Set receiver gain */ + if (prog_args.rf_gain > 0) { + srsran_rf_set_rx_gain(&rf, prog_args.rf_gain); + } else { + printf("Starting AGC thread...\n"); + if (srsran_rf_start_gain_thread(&rf, false)) { + ERROR("Error opening rf"); + exit(-1); + } + srsran_rf_set_rx_gain(&rf, srsran_rf_get_rx_gain(&rf)); + cell_detect_config.init_agc = srsran_rf_get_rx_gain(&rf); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + signal(SIGINT, sig_int_handler); + + /* set receiver frequency */ + printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq) / 1000000); + srsran_rf_set_rx_freq(&rf, prog_args.rf_nof_rx_ant, prog_args.rf_freq + prog_args.file_offset_freq); + + uint32_t ntrial = 0; + do { + ret = rf_search_and_decode_mib( + &rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &search_cell_cfo); + if (ret < 0) { + ERROR("Error searching for cell"); + exit(-1); + } else if (ret == 0 && !go_exit) { + printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++); + } + } while (ret == 0 && !go_exit); + + if (go_exit) { + srsran_rf_close(&rf); + exit(0); + } + + /* set sampling frequency */ + int srate = srsran_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + float srate_rf = srsran_rf_set_rx_srate(&rf, (double)srate); + if (srate_rf != srate) { + ERROR("Could not set sampling rate"); + exit(-1); + } + } else { + ERROR("Invalid number of PRB %d", cell.nof_prb); + exit(-1); + } + + INFO("Stopping RF and flushing buffer...\r"); + } +#endif + + /* If reading from file, go straight to PDSCH decoding. Otherwise, decode MIB first */ + if (prog_args.input_file_name) { + /* preset cell configuration */ + cell.id = prog_args.file_cell_id; + cell.cp = SRSRAN_CP_NORM; + cell.phich_length = SRSRAN_PHICH_NORM; + cell.phich_resources = SRSRAN_PHICH_R_1; + cell.nof_ports = prog_args.file_nof_ports; + cell.nof_prb = prog_args.file_nof_prb; + + if (srsran_ue_sync_init_file_multi(&ue_sync, + prog_args.file_nof_prb, + prog_args.input_file_name, + prog_args.file_offset_time, + prog_args.file_offset_freq, + prog_args.rf_nof_rx_ant)) { + ERROR("Error initiating ue_sync"); + exit(-1); + } + + } else { +#ifndef DISABLE_RF + int decimate = 0; + if (prog_args.decimate) { + if (prog_args.decimate > 4 || prog_args.decimate < 0) { + printf("Invalid decimation factor, setting to 1 \n"); + } else { + decimate = prog_args.decimate; + } + } + if (srsran_ue_sync_init_multi_decim(&ue_sync, + cell.nof_prb, + cell.id == 1000, + srsran_rf_recv_wrapper, + prog_args.rf_nof_rx_ant, + (void*)&rf, + decimate)) { + ERROR("Error initiating ue_sync"); + exit(-1); + } + if (srsran_ue_sync_set_cell(&ue_sync, cell)) { + ERROR("Error initiating ue_sync"); + exit(-1); + } +#endif + } + + uint32_t max_num_samples = 3 * SRSRAN_SF_LEN_PRB(cell.nof_prb); /// Length in complex samples + for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) { + sf_buffer[i] = srsran_vec_cf_malloc(max_num_samples); + } + srsran_ue_mib_t ue_mib; + if (srsran_ue_mib_init(&ue_mib, sf_buffer[0], cell.nof_prb)) { + ERROR("Error initaiting UE MIB decoder"); + exit(-1); + } + if (srsran_ue_mib_set_cell(&ue_mib, cell)) { + ERROR("Error initaiting UE MIB decoder"); + exit(-1); + } + + if (srsran_ue_dl_init(&ue_dl, sf_buffer, cell.nof_prb, prog_args.rf_nof_rx_ant)) { + ERROR("Error initiating UE downlink processing module"); + exit(-1); + } + if (srsran_ue_dl_set_cell(&ue_dl, cell)) { + ERROR("Error initiating UE downlink processing module"); + exit(-1); + } + + // Disable CP based CFO estimation during find + ue_sync.cfo_current_value = search_cell_cfo / 15000; + ue_sync.cfo_is_copied = true; + ue_sync.cfo_correct_enable_find = true; + srsran_sync_set_cfo_cp_enable(&ue_sync.sfind, false, 0); + + ZERO_OBJECT(ue_dl_cfg); + ZERO_OBJECT(dl_sf); + ZERO_OBJECT(pdsch_cfg); + + pdsch_cfg.meas_evm_en = true; + + if (cell.frame_type == SRSRAN_TDD && prog_args.tdd_special_sf >= 0 && prog_args.sf_config >= 0) { + dl_sf.tdd_config.ss_config = prog_args.tdd_special_sf; + dl_sf.tdd_config.sf_config = prog_args.sf_config; + dl_sf.tdd_config.configured = true; + } + + srsran_chest_dl_cfg_t chest_pdsch_cfg = {}; + chest_pdsch_cfg.cfo_estimate_enable = prog_args.enable_cfo_ref; + chest_pdsch_cfg.cfo_estimate_sf_mask = 1023; + chest_pdsch_cfg.estimator_alg = srsran_chest_dl_str2estimator_alg(prog_args.estimator_alg); + chest_pdsch_cfg.sync_error_enable = true; + + // Special configuration for MBSFN channel estimation + srsran_chest_dl_cfg_t chest_mbsfn_cfg = {}; + chest_mbsfn_cfg.filter_type = SRSRAN_CHEST_FILTER_TRIANGLE; + chest_mbsfn_cfg.filter_coef[0] = 0.1; + chest_mbsfn_cfg.estimator_alg = SRSRAN_ESTIMATOR_ALG_INTERPOLATE; + chest_mbsfn_cfg.noise_alg = SRSRAN_NOISE_ALG_PSS; + + // Allocate softbuffer buffers + srsran_softbuffer_rx_t rx_softbuffers[SRSRAN_MAX_CODEWORDS]; + for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + pdsch_cfg.softbuffers.rx[i] = &rx_softbuffers[i]; + srsran_softbuffer_rx_init(pdsch_cfg.softbuffers.rx[i], cell.nof_prb); + } + + pdsch_cfg.rnti = prog_args.rnti; + + /* Configure MBSFN area id and non-MBSFN Region */ + if (prog_args.mbsfn_area_id > -1) { + srsran_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id); + srsran_ue_dl_set_non_mbsfn_region(&ue_dl, prog_args.non_mbsfn_region); + } + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + init_plots(cell); + sleep(1); + } +#endif /* ENABLE_GUI */ + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + srsran_rf_start_rx_stream(&rf, false); + } +#endif + +#ifndef DISABLE_RF + if (prog_args.rf_gain < 0 && !prog_args.input_file_name) { + srsran_rf_info_t* rf_info = srsran_rf_get_info(&rf); + srsran_ue_sync_start_agc(&ue_sync, + srsran_rf_set_rx_gain_th_wrapper_, + rf_info->min_rx_gain, + rf_info->max_rx_gain, + cell_detect_config.init_agc); + } +#endif +#ifdef PRINT_CHANGE_SCHEDULING + srsran_ra_dl_grant_t old_dl_dci; + bzero(&old_dl_dci, sizeof(srsran_ra_dl_grant_t)); +#endif + + ue_sync.cfo_correct_enable_track = !prog_args.disable_cfo; + + srsran_pbch_decode_reset(&ue_mib.pbch); + + INFO("\nEntering main loop..."); + + // Variables for measurements + uint32_t nframes = 0; + float rsrp0 = 0.0, rsrp1 = 0.0, rsrq = 0.0, snr = 0.0, enodebrate = 0.0, uerate = 0.0, procrate = 0.0, + sinr[SRSRAN_MAX_LAYERS][SRSRAN_MAX_CODEBOOKS] = {}, sync_err[SRSRAN_MAX_PORTS][SRSRAN_MAX_PORTS] = {}; + bool decode_pdsch = false; + + for (int i = 0; i < SRSRAN_MAX_LAYERS; i++) { + srsran_vec_f_zero(sinr[i], SRSRAN_MAX_CODEBOOKS); + } + + /* Main loop */ + uint64_t sf_cnt = 0; + uint32_t sfn = 0; + uint32_t last_decoded_tm = 0; + while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { + char input[128]; + PRINT_LINE_INIT(); + + fd_set set; + FD_ZERO(&set); + FD_SET(0, &set); + + struct timeval to; + to.tv_sec = 0; + to.tv_usec = 0; + + /* Set default verbose level */ + set_srsran_verbose_level(prog_args.verbose); + int n = select(1, &set, NULL, NULL, &to); + if (n == 1) { + /* If a new line is detected set verbose level to Debug */ + if (fgets(input, sizeof(input), stdin)) { + set_srsran_verbose_level(SRSRAN_VERBOSE_DEBUG); + pkt_errors = 0; + pkt_total = 0; + nof_detected = 0; + nof_trials = 0; + } + } + + cf_t* buffers[SRSRAN_MAX_CHANNELS] = {}; + for (int p = 0; p < SRSRAN_MAX_PORTS; p++) { + buffers[p] = sf_buffer[p]; + } + ret = srsran_ue_sync_zerocopy(&ue_sync, buffers, max_num_samples); + if (ret < 0) { + ERROR("Error calling srsran_ue_sync_work()"); + } + +#ifdef CORRECT_SAMPLE_OFFSET + float sample_offset = + (float)srsran_ue_sync_get_last_sample_offset(&ue_sync) + srsran_ue_sync_get_sfo(&ue_sync) / 1000; + srsran_ue_dl_set_sample_offset(&ue_dl, sample_offset); +#endif + + /* srsran_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ + if (ret == 1) { + bool acks[SRSRAN_MAX_CODEWORDS] = {false}; + struct timeval t[3]; + + uint32_t sf_idx = srsran_ue_sync_get_sfidx(&ue_sync); + + switch (state) { + case DECODE_MIB: + if (sf_idx == 0) { + uint8_t bch_payload[SRSRAN_BCH_PAYLOAD_LEN]; + int sfn_offset; + n = srsran_ue_mib_decode(&ue_mib, bch_payload, NULL, &sfn_offset); + if (n < 0) { + ERROR("Error decoding UE MIB"); + exit(-1); + } else if (n == SRSRAN_UE_MIB_FOUND) { + srsran_pbch_mib_unpack(bch_payload, &cell, &sfn); + srsran_cell_fprint(stdout, &cell, sfn); + printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset); + sfn = (sfn + sfn_offset) % 1024; + state = DECODE_PDSCH; + } + } + break; + case DECODE_PDSCH: + + if (prog_args.rnti != SRSRAN_SIRNTI) { + decode_pdsch = true; + if (srsran_sfidx_tdd_type(dl_sf.tdd_config, sf_idx) == SRSRAN_TDD_SF_U) { + decode_pdsch = false; + } + } else { + /* We are looking for SIB1 Blocks, search only in appropiate places */ + if ((sf_idx == 5 && (sfn % 2) == 0) || mch_table[sf_idx] == 1) { + decode_pdsch = true; + } else { + decode_pdsch = false; + } + } + + uint32_t tti = sfn * 10 + sf_idx; + + gettimeofday(&t[1], NULL); + if (decode_pdsch) { + srsran_sf_t sf_type; + if (mch_table[sf_idx] == 0 || prog_args.mbsfn_area_id < 0) { // Not an MBSFN subframe + sf_type = SRSRAN_SF_NORM; + + // Set PDSCH channel estimation + ue_dl_cfg.chest_cfg = chest_pdsch_cfg; + } else { + sf_type = SRSRAN_SF_MBSFN; + + // Set MBSFN channel estimation + ue_dl_cfg.chest_cfg = chest_mbsfn_cfg; + } + + n = 0; + for (uint32_t tm = 0; tm < 4 && !n; tm++) { + dl_sf.tti = tti; + dl_sf.sf_type = sf_type; + ue_dl_cfg.cfg.tm = (srsran_tm_t)tm; + ue_dl_cfg.cfg.pdsch.use_tbs_index_alt = prog_args.enable_256qam; + + if ((ue_dl_cfg.cfg.tm == SRSRAN_TM1 && cell.nof_ports == 1) || + (ue_dl_cfg.cfg.tm > SRSRAN_TM1 && cell.nof_ports > 1)) { + n = srsran_ue_dl_find_and_decode(&ue_dl, &dl_sf, &ue_dl_cfg, &pdsch_cfg, data, acks); + if (n > 0) { + nof_detected++; + last_decoded_tm = tm; + for (uint32_t tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { + if (pdsch_cfg.grant.tb[tb].enabled) { + if (!acks[tb]) { + if (sf_type == SRSRAN_SF_NORM) { + pkt_errors++; + } else { + pmch_pkt_errors++; + } + } + if (sf_type == SRSRAN_SF_NORM) { + pkt_total++; + } else { + pmch_pkt_total++; + } + } + } + } + } + } + // Feed-back ue_sync with chest_dl CFO estimation + if (sf_idx == 5 && prog_args.enable_cfo_ref) { + srsran_ue_sync_set_cfo_ref(&ue_sync, ue_dl.chest_res.cfo); + } + + gettimeofday(&t[2], NULL); + get_time_interval(t); + + if (n > 0) { + /* Send data if socket active */ + if (prog_args.net_port > 0) { + if (sf_idx == 1) { + srsran_netsink_write(&net_sink, data[0], 1 + (n - 1) / 8); + } else { + // TODO: UDP Data transmission does not work + for (uint32_t tb = 0; tb < SRSRAN_MAX_CODEWORDS; tb++) { + if (pdsch_cfg.grant.tb[tb].enabled) { + srsran_netsink_write(&net_sink, data[tb], 1 + (pdsch_cfg.grant.tb[tb].tbs - 1) / 8); + } + } + } + } +#ifdef PRINT_CHANGE_SCHEDULING + if (pdsch_cfg.dci.cw[0].mcs_idx != old_dl_dci.cw[0].mcs_idx || + memcmp(&pdsch_cfg.dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srsran_ra_type0_t)) || + memcmp(&pdsch_cfg.dci.type1_alloc, &old_dl_dci.type1_alloc, sizeof(srsran_ra_type1_t)) || + memcmp(&pdsch_cfg.dci.type2_alloc, &old_dl_dci.type2_alloc, sizeof(srsran_ra_type2_t))) { + old_dl_dci = pdsch_cfg.dci; + fflush(stdout); + printf("DCI %s\n", srsran_dci_format_string(pdsch_cfg.dci.dci_format)); + srsran_ra_pdsch_fprint(stdout, &old_dl_dci, cell.nof_prb); + } +#endif + } + + nof_trials++; + + uint32_t enb_bits = ((pdsch_cfg.grant.tb[0].enabled ? pdsch_cfg.grant.tb[0].tbs : 0) + + (pdsch_cfg.grant.tb[1].enabled ? pdsch_cfg.grant.tb[1].tbs : 0)); + uint32_t ue_bits = ((acks[0] ? pdsch_cfg.grant.tb[0].tbs : 0) + (acks[1] ? pdsch_cfg.grant.tb[1].tbs : 0)); + rsrq = SRSRAN_VEC_EMA(ue_dl.chest_res.rsrp_dbm, rsrq, 0.1f); + rsrp0 = SRSRAN_VEC_EMA(ue_dl.chest_res.rsrp_port_dbm[0], rsrp0, 0.05f); + rsrp1 = SRSRAN_VEC_EMA(ue_dl.chest_res.rsrp_port_dbm[1], rsrp1, 0.05f); + snr = SRSRAN_VEC_EMA(ue_dl.chest_res.snr_db, snr, 0.05f); + enodebrate = SRSRAN_VEC_EMA(enb_bits / 1000.0f, enodebrate, 0.05f); + uerate = SRSRAN_VEC_EMA(ue_bits / 1000.0f, uerate, 0.001f); + if (chest_pdsch_cfg.sync_error_enable) { + for (uint32_t i = 0; i < cell.nof_ports; i++) { + for (uint32_t j = 0; j < prog_args.rf_nof_rx_ant; j++) { + sync_err[i][j] = SRSRAN_VEC_EMA(ue_dl.chest.sync_err[i][j], sync_err[i][j], 0.001f); + if (!isnormal(sync_err[i][j])) { + sync_err[i][j] = 0.0f; + } + } + } + } + float elapsed = (float)t[0].tv_usec + t[0].tv_sec * 1.0e+6f; + if (elapsed != 0.0f) { + procrate = SRSRAN_VEC_EMA(ue_bits / elapsed, procrate, 0.01f); + } + + nframes++; + if (isnan(rsrq)) { + rsrq = 0; + } + if (isnan(snr)) { + snr = 0; + } + if (isnan(rsrp0)) { + rsrp0 = 0; + } + if (isnan(rsrp1)) { + rsrp1 = 0; + } + } + + // Plot and Printf + if (sf_idx == 5) { + float gain = prog_args.rf_gain; + if (gain < 0) { + gain = srsran_convert_power_to_dB(srsran_agc_get_gain(&ue_sync.agc)); + } + + /* Print transmission scheme */ + + /* Print basic Parameters */ + PRINT_LINE(" CFO: %+7.2f Hz", srsran_ue_sync_get_cfo(&ue_sync)); + PRINT_LINE(" RSRP: %+5.1f dBm | %+5.1f dBm", rsrp0, rsrp1); + PRINT_LINE(" SNR: %+5.1f dB", snr); + PRINT_LINE(" TM: %d", last_decoded_tm + 1); + PRINT_LINE( + " Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); + PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float)nof_detected / nof_trials)); + PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float)100 * pkt_errors / pkt_total); + PRINT_LINE(" PDSCH-EVM: %5.2f%%", ue_dl.pdsch.avg_evm); + + if (prog_args.mbsfn_area_id > -1) { + PRINT_LINE(" PMCH-BLER: %5.2f%%", (float)100 * pkt_errors / pmch_pkt_total); + } + + PRINT_LINE(" TB 0: mcs=%d; tbs=%d", pdsch_cfg.grant.tb[0].mcs_idx, pdsch_cfg.grant.tb[0].tbs); + PRINT_LINE(" TB 1: mcs=%d; tbs=%d", pdsch_cfg.grant.tb[1].mcs_idx, pdsch_cfg.grant.tb[1].tbs); + + /* MIMO: if tx and rx antennas are bigger than 1 */ + if (cell.nof_ports > 1 && ue_dl.pdsch.nof_rx_antennas > 1) { + uint32_t ri = 0; + float cn = 0; + /* Compute condition number */ + if (srsran_ue_dl_select_ri(&ue_dl, &ri, &cn)) { + /* Condition number calculation is not supported for the number of tx & rx antennas*/ + PRINT_LINE(" κ: NA"); + } else { + /* Print condition number */ + PRINT_LINE(" κ: %.1f dB, RI=%d (Condition number, 0 dB => Best)", cn, ri); + } + PRINT_LINE(""); + } + if (chest_pdsch_cfg.sync_error_enable) { + for (uint32_t i = 0; i < cell.nof_ports; i++) { + for (uint32_t j = 0; j < prog_args.rf_nof_rx_ant; j++) { + PRINT_LINE("sync_err[%d][%d]=%f", i, j, sync_err[i][j]); + } + } + } + PRINT_LINE("Press enter maximum printing debug log of 1 subframe."); + PRINT_LINE(""); + PRINT_LINE_RESET_CURSOR(); + } + break; + } + if (sf_idx == 9) { + sfn++; + if (sfn == 1024) { + sfn = 0; + PRINT_LINE_ADVANCE_CURSOR(); + pkt_errors = 0; + pkt_total = 0; + pmch_pkt_errors = 0; + pmch_pkt_total = 0; + } + } + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + if ((sfn % 3) == 0 && decode_pdsch) { + plot_sf_idx = sf_idx; + plot_track = true; + sem_post(&plot_sem); + } + } +#endif /* ENABLE_GUI */ + } else if (ret == 0) { + printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", + srsran_sync_get_peak_value(&ue_sync.sfind), + ue_sync.frame_total_cnt, + ue_sync.state); +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + plot_sf_idx = srsran_ue_sync_get_sfidx(&ue_sync); + plot_track = false; + sem_post(&plot_sem); + } +#endif /* ENABLE_GUI */ + } + + sf_cnt++; + } // Main loop + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + if (!pthread_kill(plot_thread, 0)) { + pthread_kill(plot_thread, SIGHUP); + pthread_join(plot_thread, NULL); + } + } +#endif + srsran_ue_dl_free(&ue_dl); + srsran_ue_sync_free(&ue_sync); + for (int i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + } + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + srsran_ue_mib_free(&ue_mib); + srsran_rf_close(&rf); + } +#endif + + printf("\nBye\n"); + exit(0); +} + +/********************************************************************** + * Plotting Functions + ***********************************************************************/ +#ifdef ENABLE_GUI + +plot_real_t p_sync, pce; +plot_scatter_t pscatequal, pscatequal_pdcch, pscatequal_pmch; + +static float tmp_plot[110 * 15 * 2048]; +static float tmp_plot2[110 * 15 * 2048]; + +void* plot_thread_run(void* arg) +{ + int i; + uint32_t nof_re = SRSRAN_SF_LEN_RE(ue_dl.cell.nof_prb, ue_dl.cell.cp); + + sdrgui_init(); + + plot_scatter_init(&pscatequal); + plot_scatter_setTitle(&pscatequal, "PDSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal, -4, 4); + plot_scatter_setYAxisScale(&pscatequal, -4, 4); + + plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0); + + if (enable_mbsfn_plot) { + plot_scatter_init(&pscatequal_pmch); + plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4); + plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4); + plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1); + } + + if (!prog_args.disable_plots_except_constellation) { + plot_real_init(&pce); + plot_real_setTitle(&pce, "Channel Response - Magnitude"); + plot_real_setLabels(&pce, "Index", "dB"); + plot_real_setYAxisScale(&pce, -40, 40); + + plot_real_init(&p_sync); + plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); + plot_real_setYAxisScale(&p_sync, 0, 1); + + plot_scatter_init(&pscatequal_pdcch); + plot_scatter_setTitle(&pscatequal_pdcch, "PDCCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4); + plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4); + + plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, (enable_mbsfn_plot) ? 2 : 1); + plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0); + plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1); + } + + while (1) { + sem_wait(&plot_sem); + + uint32_t nof_symbols = pdsch_cfg.grant.nof_re; + if (!prog_args.disable_plots_except_constellation) { + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = srsran_convert_amplitude_to_dB(cabsf(ue_dl.sf_symbols[0][i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + int sz = srsran_symbol_sz(ue_dl.cell.nof_prb); + if (sz > 0) { + srsran_vec_f_zero(tmp_plot2, sz); + } + int g = (sz - 12 * ue_dl.cell.nof_prb) / 2; + for (i = 0; i < 12 * ue_dl.cell.nof_prb; i++) { + tmp_plot2[g + i] = srsran_convert_amplitude_to_dB(cabsf(ue_dl.chest_res.ce[0][0][i])); + if (isinf(tmp_plot2[g + i])) { + tmp_plot2[g + i] = -80; + } + } + plot_real_setNewData(&pce, tmp_plot2, sz); + + if (!prog_args.input_file_name) { + if (plot_track) { + srsran_pss_t* pss_obj = srsran_sync_get_cur_pss_obj(&ue_sync.strack); + int max = srsran_vec_max_fi(pss_obj->conv_output_avg, pss_obj->frame_size + pss_obj->fft_size - 1); + srsran_vec_sc_prod_fff(pss_obj->conv_output_avg, + 1 / pss_obj->conv_output_avg[max], + tmp_plot2, + pss_obj->frame_size + pss_obj->fft_size - 1); + plot_real_setNewData(&p_sync, tmp_plot2, pss_obj->frame_size); + } else { + int max = srsran_vec_max_fi(ue_sync.sfind.pss.conv_output_avg, + ue_sync.sfind.pss.frame_size + ue_sync.sfind.pss.fft_size - 1); + srsran_vec_sc_prod_fff(ue_sync.sfind.pss.conv_output_avg, + 1 / ue_sync.sfind.pss.conv_output_avg[max], + tmp_plot2, + ue_sync.sfind.pss.frame_size + ue_sync.sfind.pss.fft_size - 1); + plot_real_setNewData(&p_sync, tmp_plot2, ue_sync.sfind.pss.frame_size); + } + } + + plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36 * ue_dl.pdcch.nof_cce[0]); + } + + plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols); + + if (enable_mbsfn_plot) { + plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols); + } + + if (plot_sf_idx == 1) { + if (prog_args.net_port_signal > 0) { + srsran_netsink_write( + &net_sink_signal, &sf_buffer[srsran_ue_sync_sf_len(&ue_sync) / 7], srsran_ue_sync_sf_len(&ue_sync)); + } + } + } + return NULL; +} + +void init_plots() +{ + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, NULL, plot_thread_run, NULL)) { + perror("pthread_create"); + exit(-1); + } +} + +#endif /* ENABLE_GUI */ diff --git a/srsRAN_4G_mirror/lib/examples/pssch_ue.c b/srsRAN_4G_mirror/lib/examples/pssch_ue.c new file mode 100644 index 0000000..d45ccb4 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/pssch_ue.c @@ -0,0 +1,645 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/common/pcap.h" +#include "srsran/phy/ch_estimation/chest_sl.h" +#include "srsran/phy/common/phy_common_sl.h" +#include "srsran/phy/dft/ofdm.h" +#include "srsran/phy/phch/pscch.h" +#include "srsran/phy/phch/pssch.h" +#include "srsran/phy/phch/ra_sl.h" +#include "srsran/phy/phch/sci.h" +#include "srsran/phy/rf/rf.h" +#include "srsran/phy/ue/ue_sync.h" +#include "srsran/phy/utils/bit.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" + +#define PCAP_FILENAME "/tmp/pssch.pcap" + +static bool keep_running = true; + +static srsran_cell_sl_t cell_sl = {.nof_prb = 50, .tm = SRSRAN_SIDELINK_TM4, .cp = SRSRAN_CP_NORM, .N_sl_id = 0}; + +typedef struct { + bool use_standard_lte_rates; + bool disable_plots; + char* input_file_name; + uint32_t file_start_sf_idx; + uint32_t nof_rx_antennas; + char* rf_dev; + char* rf_args; + double rf_freq; + float rf_gain; + + // Sidelink specific args + uint32_t size_sub_channel; + uint32_t num_sub_channel; +} prog_args_t; + +void args_default(prog_args_t* args) +{ + args->disable_plots = false; + args->use_standard_lte_rates = false; + args->input_file_name = NULL; + args->file_start_sf_idx = 0; + args->nof_rx_antennas = 1; + args->rf_dev = ""; + args->rf_dev = ""; + args->rf_args = ""; + args->rf_freq = 5.92e9; + args->rf_gain = 50; + args->size_sub_channel = 10; + args->num_sub_channel = 5; +} + +static srsran_pscch_t pscch = {}; // Defined global for plotting thread +static srsran_pssch_t pssch = {}; + +#ifndef DISABLE_RF +static srsran_rf_t radio; +#endif // DISABLE_RF + +static prog_args_t prog_args; + +static srsran_filesource_t fsrc = {}; + +#ifdef ENABLE_GUI +#include "srsgui/srsgui.h" +void init_plots(); +static pthread_t plot_thread; +static sem_t plot_sem; +#endif // ENABLE_GUI + +void sig_int_handler(int signo) +{ + printf("SIGINT received. Exiting...\n"); + if (signo == SIGINT) { + keep_running = false; + } else if (signo == SIGSEGV) { + exit(1); + } +} + +void pcap_pack_and_write(FILE* pcap_file, + uint8_t* pdu, + uint32_t pdu_len_bytes, + uint8_t reTX, + bool crc_ok, + uint32_t tti, + uint16_t crnti, + uint8_t direction, + uint8_t rnti_type) +{ + MAC_Context_Info_t context = {.radioType = FDD_RADIO, + .direction = direction, + .rntiType = rnti_type, + .rnti = crnti, + .ueid = 1, + .isRetx = reTX, + .crcStatusOK = crc_ok, + .sysFrameNumber = (uint16_t)(tti / SRSRAN_NOF_SF_X_FRAME), + .subFrameNumber = (uint16_t)(tti % SRSRAN_NOF_SF_X_FRAME), + .nbiotMode = 0}; + if (pdu) { + LTE_PCAP_MAC_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } +} + +void usage(prog_args_t* args, char* prog) +{ + printf("Usage: %s [agrnmv] -f rx_frequency_hz\n", prog); + printf("\t-a RF args [Default %s]\n", args->rf_args); + printf("\t-d RF devicename [Default %s]\n", args->rf_dev); + printf("\t-i input_file_name\n"); + printf("\t-m Start subframe_idx [Default %d]\n", args->file_start_sf_idx); + printf("\t-g RF Gain [Default %.2f dB]\n", args->rf_gain); + printf("\t-A nof_rx_antennas [Default %d]\n", args->nof_rx_antennas); + printf("\t-c N_sl_id [Default %d]\n", cell_sl.N_sl_id); + printf("\t-p nof_prb [Default %d]\n", cell_sl.nof_prb); + printf("\t-s size_sub_channel [Default for 50 prbs %d]\n", args->size_sub_channel); + printf("\t-n num_sub_channel [Default for 50 prbs %d]\n", args->num_sub_channel); + printf("\t-t Sidelink transmission mode {1,2,3,4} [Default %d]\n", (cell_sl.tm + 1)); + printf("\t-r use_standard_lte_rates [Default %i]\n", args->use_standard_lte_rates); +#ifdef ENABLE_GUI + printf("\t-w disable plots [Default enabled]\n"); +#endif + printf("\t-v srsran_verbose\n"); +} + +void parse_args(prog_args_t* args, int argc, char** argv) +{ + int opt; + args_default(args); + + while ((opt = getopt(argc, argv, "acdimgpvwrxfA")) != -1) { + switch (opt) { + case 'a': + args->rf_args = argv[optind]; + break; + case 'c': + cell_sl.N_sl_id = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'd': + args->rf_dev = argv[optind]; + break; + case 'i': + args->input_file_name = argv[optind]; + break; + case 'm': + args->file_start_sf_idx = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'g': + args->rf_gain = strtof(argv[optind], NULL); + break; + case 'p': + cell_sl.nof_prb = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'f': + args->rf_freq = strtof(argv[optind], NULL); + break; + case 'A': + args->nof_rx_antennas = (int32_t)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + case 'w': + args->disable_plots = true; + break; + case 'r': + args->use_standard_lte_rates = true; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->rf_freq < 0 && args->input_file_name == NULL) { + usage(args, argv[0]); + exit(-1); + } +} + +#ifndef DISABLE_RF +int srsran_rf_recv_wrapper(void* h, cf_t* data[SRSRAN_MAX_PORTS], uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + void* ptr[SRSRAN_MAX_PORTS]; + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + ptr[i] = data[i]; + } + return srsran_rf_recv_with_time_multi(h, ptr, nsamples, true, &t->full_secs, &t->frac_secs); +} +#endif // DISABLE_RF + +int main(int argc, char** argv) +{ + signal(SIGINT, sig_int_handler); + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + + uint32_t num_decoded_sci = 0; + uint32_t num_decoded_tb = 0; + + parse_args(&prog_args, argc, argv); + + FILE* pcap_file = DLT_PCAP_Open(MAC_LTE_DLT, PCAP_FILENAME); + + srsran_use_standard_symbol_size(prog_args.use_standard_lte_rates); + + srsran_sl_comm_resource_pool_t sl_comm_resource_pool; + if (srsran_sl_comm_resource_pool_get_default_config(&sl_comm_resource_pool, cell_sl) != SRSRAN_SUCCESS) { + ERROR("Error initializing sl_comm_resource_pool"); + return SRSRAN_ERROR; + } + + if (prog_args.input_file_name) { + if (srsran_filesource_init(&fsrc, prog_args.input_file_name, SRSRAN_COMPLEX_FLOAT_BIN)) { + printf("Error opening file %s\n", prog_args.input_file_name); + return SRSRAN_ERROR; + } + } + +#ifndef DISABLE_RF + if (!prog_args.input_file_name) { + printf("Opening RF device...\n"); + + if (srsran_rf_open_devname(&radio, prog_args.rf_dev, prog_args.rf_args, prog_args.nof_rx_antennas)) { + ERROR("Error opening rf"); + exit(-1); + } + + srsran_rf_set_rx_gain(&radio, prog_args.rf_gain); + + printf("Set RX freq: %.6f MHz\n", + srsran_rf_set_rx_freq(&radio, prog_args.nof_rx_antennas, prog_args.rf_freq) / 1e6); + printf("Set RX gain: %.1f dB\n", prog_args.rf_gain); + int srate = srsran_sampling_freq_hz(cell_sl.nof_prb); + + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + float srate_rf = srsran_rf_set_rx_srate(&radio, (double)srate); + if (srate_rf != srate) { + ERROR("Could not set sampling rate"); + exit(-1); + } + } else { + ERROR("Invalid number of PRB %d", cell_sl.nof_prb); + exit(-1); + } + } +#endif // DISABLE_RF + + // allocate Rx buffers for 1ms worth of samples + uint32_t sf_len = SRSRAN_SF_LEN_PRB(cell_sl.nof_prb); + printf("Using a SF len of %d samples\n", sf_len); + + cf_t* rx_buffer[SRSRAN_MAX_CHANNELS] = {}; //< For radio to receive samples + cf_t* sf_buffer[SRSRAN_MAX_PORTS] = {NULL}; ///< For OFDM object to store subframe after FFT + + for (int i = 0; i < prog_args.nof_rx_antennas; i++) { + rx_buffer[i] = srsran_vec_cf_malloc(sf_len); + if (!rx_buffer[i]) { + perror("malloc"); + exit(-1); + } + sf_buffer[i] = srsran_vec_cf_malloc(sf_len); + if (!sf_buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + uint32_t sf_n_re = SRSRAN_CP_NSYMB(SRSRAN_CP_NORM) * SRSRAN_NRE * 2 * cell_sl.nof_prb; + cf_t* equalized_sf_buffer = srsran_vec_malloc(sizeof(cf_t) * sf_n_re); + + // RX + srsran_ofdm_t fft[SRSRAN_MAX_PORTS]; + srsran_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.nof_prb = cell_sl.nof_prb; + ofdm_cfg.cp = SRSRAN_CP_NORM; + ofdm_cfg.rx_window_offset = 0.0f; + ofdm_cfg.normalize = true; + ofdm_cfg.sf_type = SRSRAN_SF_NORM; + ofdm_cfg.freq_shift_f = -0.5; + for (int i = 0; i < prog_args.nof_rx_antennas; i++) { + ofdm_cfg.in_buffer = rx_buffer[0]; + ofdm_cfg.out_buffer = sf_buffer[0]; + + if (srsran_ofdm_rx_init_cfg(&fft[i], &ofdm_cfg)) { + ERROR("Error initiating FFT"); + goto clean_exit; + } + } + + // SCI + srsran_sci_t sci; + srsran_sci_init(&sci, &cell_sl, &sl_comm_resource_pool); + uint8_t sci_rx[SRSRAN_SCI_MAX_LEN] = {}; + char sci_msg[SRSRAN_SCI_MSG_MAX_LEN] = {}; + + // init PSCCH object + if (srsran_pscch_init(&pscch, SRSRAN_MAX_PRB) != SRSRAN_SUCCESS) { + ERROR("Error in PSCCH init"); + return SRSRAN_ERROR; + } + + if (srsran_pscch_set_cell(&pscch, cell_sl) != SRSRAN_SUCCESS) { + ERROR("Error in PSCCH set cell"); + return SRSRAN_ERROR; + } + + // PSCCH Channel estimation + srsran_chest_sl_cfg_t pscch_chest_sl_cfg = {}; + srsran_chest_sl_t pscch_chest = {}; + if (srsran_chest_sl_init(&pscch_chest, SRSRAN_SIDELINK_PSCCH, cell_sl, &sl_comm_resource_pool) != SRSRAN_SUCCESS) { + ERROR("Error in chest PSCCH init"); + return SRSRAN_ERROR; + } + + if (srsran_pssch_init(&pssch, &cell_sl, &sl_comm_resource_pool) != SRSRAN_SUCCESS) { + ERROR("Error initializing PSSCH"); + return SRSRAN_ERROR; + } + + srsran_chest_sl_cfg_t pssch_chest_sl_cfg = {}; + srsran_chest_sl_t pssch_chest = {}; + if (srsran_chest_sl_init(&pssch_chest, SRSRAN_SIDELINK_PSSCH, cell_sl, &sl_comm_resource_pool) != SRSRAN_SUCCESS) { + ERROR("Error in chest PSSCH init"); + return SRSRAN_ERROR; + } + + uint8_t tb[SRSRAN_SL_SCH_MAX_TB_LEN] = {}; + uint8_t packed_tb[SRSRAN_SL_SCH_MAX_TB_LEN / 8] = {}; + +#ifndef DISABLE_RF + srsran_ue_sync_t ue_sync = {}; + if (!prog_args.input_file_name) { + srsran_cell_t cell = {}; + cell.nof_prb = cell_sl.nof_prb; + cell.cp = SRSRAN_CP_NORM; + cell.nof_ports = 1; + + if (srsran_ue_sync_init_multi_decim_mode(&ue_sync, + cell.nof_prb, + false, + srsran_rf_recv_wrapper, + prog_args.nof_rx_antennas, + (void*)&radio, + 1, + SYNC_MODE_GNSS)) { + fprintf(stderr, "Error initiating sync_gnss\n"); + exit(-1); + } + + if (srsran_ue_sync_set_cell(&ue_sync, cell)) { + ERROR("Error initiating ue_sync"); + exit(-1); + } + + srsran_rf_start_rx_stream(&radio, false); + } +#endif + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + init_plots(&pscch); + sleep(1); + } +#endif + + uint32_t subframe_count = 0; + uint32_t pscch_prb_start_idx = 0; + + uint32_t current_sf_idx = 0; + if (prog_args.input_file_name) { + current_sf_idx = prog_args.file_start_sf_idx; + } + + while (keep_running) { + if (prog_args.input_file_name) { + // read subframe from file + int nread = srsran_filesource_read(&fsrc, rx_buffer[0], sf_len); + if (nread < 0) { + fprintf(stderr, "Error reading from file\n"); + goto clean_exit; + } else if (nread == 0) { + goto clean_exit; + } else if (nread < sf_len) { + fprintf(stderr, "Couldn't read entire subframe. Still processing ..\n"); + nread = -1; + } + } else { +#ifndef DISABLE_RF + // receive subframe from radio + int ret = srsran_ue_sync_zerocopy(&ue_sync, rx_buffer, sf_len); + if (ret < 0) { + ERROR("Error calling srsran_ue_sync_work()"); + } + + // update SF index + current_sf_idx = srsran_ue_sync_get_sfidx(&ue_sync); +#endif // DISABLE_RF + } + + // do FFT (on first port) + srsran_ofdm_rx_sf(&fft[0]); + + for (int sub_channel_idx = 0; sub_channel_idx < sl_comm_resource_pool.num_sub_channel; sub_channel_idx++) { + pscch_prb_start_idx = sub_channel_idx * sl_comm_resource_pool.size_sub_channel; + + for (uint32_t cyclic_shift = 0; cyclic_shift <= 9; cyclic_shift += 3) { + // PSCCH Channel estimation + pscch_chest_sl_cfg.cyclic_shift = cyclic_shift; + pscch_chest_sl_cfg.prb_start_idx = pscch_prb_start_idx; + srsran_chest_sl_set_cfg(&pscch_chest, pscch_chest_sl_cfg); + srsran_chest_sl_ls_estimate_equalize(&pscch_chest, sf_buffer[0], equalized_sf_buffer); + + if (srsran_pscch_decode(&pscch, equalized_sf_buffer, sci_rx, pscch_prb_start_idx) == SRSRAN_SUCCESS) { + if (srsran_sci_format1_unpack(&sci, sci_rx) == SRSRAN_SUCCESS) { + srsran_sci_info(&sci, sci_msg, sizeof(sci_msg)); + fprintf(stdout, "%s", sci_msg); + + num_decoded_sci++; + + // plot PSCCH +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + sem_post(&plot_sem); + } +#endif + + // Decode PSSCH + uint32_t sub_channel_start_idx = 0; + uint32_t L_subCH = 0; + srsran_ra_sl_type0_from_riv( + sci.riv, sl_comm_resource_pool.num_sub_channel, &L_subCH, &sub_channel_start_idx); + + // 3GPP TS 36.213 Section 14.1.1.4C + uint32_t pssch_prb_start_idx = (sub_channel_idx * sl_comm_resource_pool.size_sub_channel) + + pscch.pscch_nof_prb + sl_comm_resource_pool.start_prb_sub_channel; + uint32_t nof_prb_pssch = ((L_subCH + sub_channel_idx) * sl_comm_resource_pool.size_sub_channel) - + pssch_prb_start_idx + sl_comm_resource_pool.start_prb_sub_channel; + + // make sure PRBs are valid for DFT precoding + nof_prb_pssch = srsran_dft_precoding_get_valid_prb(nof_prb_pssch); + + uint32_t N_x_id = 0; + for (int j = 0; j < SRSRAN_SCI_CRC_LEN; j++) { + N_x_id += pscch.sci_crc[j] * exp2(SRSRAN_SCI_CRC_LEN - 1 - j); + } + + uint32_t rv_idx = 0; + if (sci.retransmission == true) { + rv_idx = 1; + } + + // PSSCH Channel estimation + pssch_chest_sl_cfg.N_x_id = N_x_id; + pssch_chest_sl_cfg.sf_idx = current_sf_idx; + pssch_chest_sl_cfg.prb_start_idx = pssch_prb_start_idx; + pssch_chest_sl_cfg.nof_prb = nof_prb_pssch; + srsran_chest_sl_set_cfg(&pssch_chest, pssch_chest_sl_cfg); + srsran_chest_sl_ls_estimate_equalize(&pssch_chest, sf_buffer[0], equalized_sf_buffer); + + srsran_pssch_cfg_t pssch_cfg = { + pssch_prb_start_idx, nof_prb_pssch, N_x_id, sci.mcs_idx, rv_idx, current_sf_idx}; + if (srsran_pssch_set_cfg(&pssch, pssch_cfg) == SRSRAN_SUCCESS) { + if (srsran_pssch_decode(&pssch, equalized_sf_buffer, tb, SRSRAN_SL_SCH_MAX_TB_LEN) == SRSRAN_SUCCESS) { + num_decoded_tb++; + + // pack bit sand write to PCAP + srsran_bit_pack_vector(tb, packed_tb, pssch.sl_sch_tb_len); + pcap_pack_and_write(pcap_file, + packed_tb, + pssch.sl_sch_tb_len / 8, + 0, + true, + current_sf_idx, + 0x1001, + DIRECTION_UPLINK, + SL_RNTI); + +#ifdef ENABLE_GUI + // plot PSSCH + if (!prog_args.disable_plots) { + sem_post(&plot_sem); + } + if (prog_args.input_file_name) { + printf("Press Enter to continue ...\n"); + getchar(); + } +#endif + } + } + } + } + if (SRSRAN_VERBOSE_ISDEBUG()) { + char filename[64]; + snprintf(filename, + 64, + "pscch_rx_syms_sf%d_shift%d_prbidx%d.bin", + subframe_count, + cyclic_shift, + pscch_prb_start_idx); + printf("Saving PSCCH symbols (%d) to %s\n", pscch.E / SRSRAN_PSCCH_QM, filename); + srsran_vec_save_file(filename, pscch.mod_symbols, pscch.E / SRSRAN_PSCCH_QM * sizeof(cf_t)); + } + } + } + + current_sf_idx = (current_sf_idx + 1) % 10; + subframe_count++; + } + +clean_exit: + printf("num_decoded_sci=%d num_decoded_tb=%d\n", num_decoded_sci, num_decoded_tb); + + if (pcap_file != NULL) { + printf("Saving PCAP file to %s\n", PCAP_FILENAME); + DLT_PCAP_Close(pcap_file); + } + +#ifdef ENABLE_GUI + if (!prog_args.disable_plots) { + sem_post(&plot_sem); + usleep(1000); + if (!pthread_kill(plot_thread, 0)) { + pthread_kill(plot_thread, SIGHUP); + pthread_join(plot_thread, NULL); + } + } + sdrgui_exit(); +#endif + +#ifndef DISABLE_RF + srsran_rf_stop_rx_stream(&radio); + srsran_rf_close(&radio); + srsran_ue_sync_free(&ue_sync); +#endif // DISABLE_RF + + srsran_sci_free(&sci); + srsran_pscch_free(&pscch); + srsran_chest_sl_free(&pscch_chest); + srsran_chest_sl_free(&pssch_chest); + + for (int i = 0; i < prog_args.nof_rx_antennas; i++) { + if (rx_buffer[i]) { + free(rx_buffer[i]); + } + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + srsran_ofdm_rx_free(&fft[i]); + } + + if (equalized_sf_buffer) { + free(equalized_sf_buffer); + } + + return SRSRAN_SUCCESS; +} + +///< Plotting Functions +#ifdef ENABLE_GUI + +plot_scatter_t pscatequal_pscch; +plot_scatter_t pscatequal_pssch; + +void* plot_thread_run(void* arg) +{ + sdrgui_init(); + + plot_scatter_init(&pscatequal_pscch); + plot_scatter_setTitle(&pscatequal_pscch, "PSCCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal_pscch, -4, 4); + plot_scatter_setYAxisScale(&pscatequal_pscch, -4, 4); + + plot_scatter_init(&pscatequal_pssch); + plot_scatter_setTitle(&pscatequal_pssch, "PSSCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal_pssch, -4, 4); + plot_scatter_setYAxisScale(&pscatequal_pssch, -4, 4); + + plot_scatter_addToWindowGrid(&pscatequal_pscch, (char*)"pssch_ue", 0, 0); + plot_scatter_addToWindowGrid(&pscatequal_pssch, (char*)"pssch_ue", 0, 1); + + while (keep_running) { + sem_wait(&plot_sem); + plot_scatter_setNewData(&pscatequal_pscch, pscch.mod_symbols, pscch.E / SRSRAN_PSCCH_QM); + if (pssch.G > 0 && pssch.Qm > 0) { + plot_scatter_setNewData(&pscatequal_pssch, pssch.symbols, pssch.G / pssch.Qm); + } + } + + return NULL; +} + +void init_plots() +{ + if (sem_init(&plot_sem, 0, 0)) { + perror("sem_init"); + exit(-1); + } + + pthread_attr_t attr; + struct sched_param param; + param.sched_priority = 0; + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_OTHER); + pthread_attr_setschedparam(&attr, ¶m); + if (pthread_create(&plot_thread, NULL, plot_thread_run, NULL)) { + perror("pthread_create"); + exit(-1); + } +} + +#endif // ENABLE_GUI diff --git a/srsRAN_4G_mirror/lib/examples/synch_file.c b/srsRAN_4G_mirror/lib/examples/synch_file.c new file mode 100644 index 0000000..8d8bdf9 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/synch_file.c @@ -0,0 +1,271 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "srsran/srsran.h" + +char* input_file_name; +char* output_file_name = "abs_corr.txt"; +int nof_frames = 100, frame_length = 9600, symbol_sz = 128; +float corr_peak_threshold = 25.0; +int out_N_id_2 = 0, force_N_id_2 = -1; + +#define CFO_AUTO -9999.0 +float force_cfo = CFO_AUTO; + +void usage(char* prog) +{ + printf("Usage: %s [olntsNfcv] -i input_file\n", prog); + printf("\t-o output_file [Default %s]\n", output_file_name); + printf("\t-l frame_length [Default %d]\n", frame_length); + printf("\t-n number of frames [Default %d]\n", nof_frames); + printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold); + printf("\t-s symbol_sz [Default %d]\n", symbol_sz); + printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2); + printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2); + printf("\t-c force_cfo [Default disabled]\n"); + printf("\t-v srsran_verbose\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) { + switch (opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'o': + output_file_name = argv[optind]; + break; + case 'n': + nof_frames = (int)strtol(argv[optind], NULL, 10); + break; + case 'l': + frame_length = (int)strtol(argv[optind], NULL, 10); + break; + case 't': + corr_peak_threshold = strtof(argv[optind], NULL); + break; + case 's': + symbol_sz = (int)strtol(argv[optind], NULL, 10); + break; + case 'N': + out_N_id_2 = (int)strtol(argv[optind], NULL, 10); + break; + case 'f': + force_N_id_2 = (int)strtol(argv[optind], NULL, 10); + break; + case 'c': + force_cfo = strtof(argv[optind], NULL); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char** argv) +{ + srsran_filesource_t fsrc; + srsran_filesink_t fsink; + srsran_pss_t pss[3]; // One for each N_id_2 + srsran_sss_t sss[3]; // One for each N_id_2 + srsran_cfo_t cfocorr; + int peak_pos[3]; + float* cfo; + float peak_value[3]; + int frame_cnt; + cf_t* input; + uint32_t m0, m1; + float m0_value, m1_value; + uint32_t N_id_2; + int sss_idx; + struct timeval tdata[3]; + int* exec_time; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + + parse_args(argc, argv); + + gettimeofday(&tdata[1], NULL); + printf("Initializing..."); + fflush(stdout); + + if (srsran_filesource_init(&fsrc, input_file_name, SRSRAN_COMPLEX_FLOAT_BIN)) { + ERROR("Error opening file %s", input_file_name); + exit(-1); + } + if (srsran_filesink_init(&fsink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN)) { + ERROR("Error opening file %s", output_file_name); + exit(-1); + } + + input = srsran_vec_cf_malloc(frame_length); + if (!input) { + perror("malloc"); + exit(-1); + } + cfo = srsran_vec_f_malloc(nof_frames); + if (!cfo) { + perror("malloc"); + exit(-1); + } + exec_time = srsran_vec_i32_malloc(nof_frames); + if (!exec_time) { + perror("malloc"); + exit(-1); + } + + if (srsran_cfo_init(&cfocorr, frame_length)) { + ERROR("Error initiating CFO"); + return -1; + } + + /* We have 2 options here: + * a) We create 3 pss objects, each initialized with a different N_id_2 + * b) We create 1 pss object which scans for each N_id_2 one after another. + * a) requries more memory but has less latency and is paralellizable. + */ + for (N_id_2 = 0; N_id_2 < 3; N_id_2++) { + if (srsran_pss_init_fft(&pss[N_id_2], frame_length, symbol_sz)) { + ERROR("Error initializing PSS object"); + exit(-1); + } + if (srsran_pss_set_N_id_2(&pss[N_id_2], N_id_2)) { + ERROR("Error initializing N_id_2"); + exit(-1); + } + if (srsran_sss_init(&sss[N_id_2], symbol_sz)) { + ERROR("Error initializing SSS object"); + exit(-1); + } + if (srsran_sss_set_N_id_2(&sss[N_id_2], N_id_2)) { + ERROR("Error initializing N_id_2"); + exit(-1); + } + } + gettimeofday(&tdata[2], NULL); + get_time_interval(tdata); + printf("done in %ld s %ld ms\n", tdata[0].tv_sec, tdata[0].tv_usec / 1000); + + printf("\n\tFr.Cnt\tN_id_2\tN_id_1\tSubf\tPSS Peak/Avg\tIdx\tm0\tm1\tCFO\n"); + printf("\t===============================================================================\n"); + + /* read all file or nof_frames */ + frame_cnt = 0; + while (frame_length == srsran_filesource_read(&fsrc, input, frame_length) && frame_cnt < nof_frames) { + gettimeofday(&tdata[1], NULL); + if (force_cfo != CFO_AUTO) { + srsran_cfo_correct(&cfocorr, input, input, force_cfo / 128); + } + + if (force_N_id_2 != -1) { + N_id_2 = force_N_id_2; + peak_pos[N_id_2] = srsran_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + } else { + for (N_id_2 = 0; N_id_2 < 3; N_id_2++) { + peak_pos[N_id_2] = srsran_pss_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); + } + float max_value = -99999; + N_id_2 = -1; + int i; + for (i = 0; i < 3; i++) { + if (peak_value[i] > max_value) { + max_value = peak_value[i]; + N_id_2 = i; + } + } + } + + /* If peak detected */ + if (peak_value[N_id_2] > corr_peak_threshold) { + sss_idx = peak_pos[N_id_2] - 2 * (symbol_sz + SRSRAN_CP_LEN(symbol_sz, SRSRAN_CP_NORM_LEN)); + if (sss_idx >= 0) { + srsran_sss_m0m1_diff(&sss[N_id_2], &input[sss_idx], &m0, &m0_value, &m1, &m1_value); + + cfo[frame_cnt] = srsran_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2] - 128]); + printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", + frame_cnt, + N_id_2, + srsran_sss_N_id_1(&sss[N_id_2], m0, m1, m1_value + m0_value), + srsran_sss_subframe(m0, m1), + peak_value[N_id_2], + peak_pos[N_id_2], + m0, + m1, + cfo[frame_cnt]); + } + } + gettimeofday(&tdata[2], NULL); + get_time_interval(tdata); + exec_time[frame_cnt] = tdata[0].tv_usec; + frame_cnt++; + } + + int i; + float avg_time = 0; + for (i = 0; i < frame_cnt; i++) { + avg_time += (float)exec_time[i]; + } + avg_time /= frame_cnt; + printf("\n"); + printf("Average exec time: %.3f ms / frame. %.3f Msamp/s (%.3f\%% CPU)\n", + avg_time / 1000, + frame_length / avg_time, + 100 * avg_time / 5000 * (9600 / (float)frame_length)); + + float cfo_mean = 0; + for (i = 0; i < frame_cnt; i++) { + cfo_mean += cfo[i] / frame_cnt * (9600 / frame_length); + } + printf("Average CFO: %.3f\n", cfo_mean); + + for (N_id_2 = 0; N_id_2 < 3; N_id_2++) { + srsran_pss_free(&pss[N_id_2]); + srsran_sss_free(&sss[N_id_2]); + } + + srsran_filesource_free(&fsrc); + srsran_filesink_free(&fsink); + + free(input); + free(cfo); + + printf("Done\n"); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/test/CMakeLists.txt b/srsRAN_4G_mirror/lib/examples/test/CMakeLists.txt new file mode 100644 index 0000000..3fef66e --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/test/CMakeLists.txt @@ -0,0 +1,73 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +######################################################################## +# NPDSCH_ENODEB/UE TESTS +######################################################################## + +SET(CTEST_OUTPUT_ON_FAILURE TRUE) + +# Run eNB and generate DL signal +# - we generate 512 DL frames +# - schedulingInfoSIB1-NB-r13 is 2, so 16 SIB repetitions are used +# - each frame contains a NPDCCH and NPDSCH with TBS=24 for RNTI 0x1234 +set(ARG "-o;/tmp/enbtest1.bin;-n;512;-t;2") +add_test(NAME enb1 + COMMAND ${CMAKE_COMMAND} -DCMD=$ "-DARG=${ARG}" -V -P ${CMAKE_CURRENT_SOURCE_DIR}/iqtests.cmake) + +# Run npdsch_npdcch file tests + +# Try to decode SIB (-k) +set(ARG "-i;/tmp/enbtest1.bin;-m;512;-t;2;-w;0;-k") +add_test(NAME npdsch_npdcch_file1 + COMMAND ${CMAKE_COMMAND} -DCMD=$ "-DARG=${ARG}" -V -P ${CMAKE_CURRENT_SOURCE_DIR}/iqtests.cmake) +# Specify test, SIB1 should be decoded once +set_property(TEST npdsch_npdcch_file1 PROPERTY PASS_REGULAR_EXPRESSION "pkt_ok=1") +set_property(TEST npdsch_npdcch_file1 APPEND PROPERTY DEPENDS enb1) + + +# Try to decode NPDCCH+NPDSCH for user +set(ARG "-i;/tmp/enbtest1.bin;-m;512;-t;2;-w;0;-r;0x1234") +add_test(NAME npdsch_npdcch_file2 + COMMAND ${CMAKE_COMMAND} -DCMD=$ "-DARG=${ARG}" -V -P ${CMAKE_CURRENT_SOURCE_DIR}/iqtests.cmake) +# Specify test +set_property(TEST npdsch_npdcch_file2 PROPERTY PASS_REGULAR_EXPRESSION "pkt_ok=512") +set_property(TEST npdsch_npdcch_file2 APPEND PROPERTY DEPENDS enb1) + +# Run eNB and generate DL signal +# - we generate 10 DL frames +# - schedulingInfoSIB1-NB-r13 is 0, so 4 SIB repetitions are used +# - i_sf is 1, so two subframes +# - i_rep is 2, so four repetitions +# - i_mcs is 4, so TBS of 120 +# - each NPDSCH lasts over 8 subframes in total, starting in sf_idx, +# so in total, two frames are needed for NPDCCH+NPDSCH, hence, 10/2=5 frames +# should be received +set(ARG "-o;/tmp/enbtest2.bin;-n;10;-t;0;-i;1;-m;4;-r;2") +add_test(NAME enb2 + COMMAND ${CMAKE_COMMAND} -DCMD=$ "-DARG=${ARG}" -V -P ${CMAKE_CURRENT_SOURCE_DIR}/iqtests.cmake) + +# Try to decode NPDCCH+NPDSCH for user +set(ARG "-i;/tmp/enbtest2.bin;-m;512;-w;0;-r;0x1234") +add_test(NAME npdsch_npdcch_file3 + COMMAND ${CMAKE_COMMAND} -DCMD=$ "-DARG=${ARG}" -V -P ${CMAKE_CURRENT_SOURCE_DIR}/iqtests.cmake) +# Specify test +set_property(TEST npdsch_npdcch_file3 PROPERTY PASS_REGULAR_EXPRESSION "pkt_ok=5") +set_property(TEST npdsch_npdcch_file3 APPEND PROPERTY DEPENDS enb2) \ No newline at end of file diff --git a/srsRAN_4G_mirror/lib/examples/test/iqtests.cmake b/srsRAN_4G_mirror/lib/examples/test/iqtests.cmake new file mode 100644 index 0000000..6787908 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/test/iqtests.cmake @@ -0,0 +1,28 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +message("CMD: " ${CMD}) +message("ARG: " ${ARG}) +execute_process(COMMAND ${CMD} ${ARG} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ) +message("RESULT: " ${result}) +message("OUTPUT: " ${output}) diff --git a/srsRAN_4G_mirror/lib/examples/usrp_capture.c b/srsRAN_4G_mirror/lib/examples/usrp_capture.c new file mode 100644 index 0000000..392cb5e --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/usrp_capture.c @@ -0,0 +1,174 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "srsran/phy/io/filesink.h" +#include "srsran/phy/rf/rf.h" +#include "srsran/srsran.h" + +static bool keep_running = true; +char* output_file_name; +char* rf_args = ""; +float rf_gain = 40.0, rf_freq = -1.0, rf_rate = 0.96e6; +int nof_samples = -1; +int nof_rx_antennas = 1; + +void int_handler(int dummy) +{ + keep_running = false; +} + +void usage(char* prog) +{ + printf("Usage: %s [agrnv] -f rx_frequency_hz -o output_file\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); + printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate); + printf("\t-n nof_samples [Default %d]\n", nof_samples); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); + printf("\t-v srsran_verbose\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) { + switch (opt) { + case 'o': + output_file_name = argv[optind]; + break; + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'r': + rf_rate = strtof(argv[optind], NULL); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'n': + nof_samples = (int)strtol(argv[optind], NULL, 10); + break; + case 'A': + nof_rx_antennas = (int)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (rf_freq < 0) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char** argv) +{ + cf_t* buffer[SRSRAN_MAX_PORTS]; + int sample_count, n; + srsran_rf_t rf; + srsran_filesink_t sink; + uint32_t buflen; + + signal(SIGINT, int_handler); + + parse_args(argc, argv); + + buflen = 4800; + sample_count = 0; + + for (int i = 0; i < nof_rx_antennas; i++) { + buffer[i] = srsran_vec_cf_malloc(buflen); + if (!buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + srsran_filesink_init(&sink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN); + + printf("Opening RF device..."); + if (srsran_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { + ERROR("Error opening rf"); + exit(-1); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + + srsran_rf_set_rx_gain(&rf, rf_gain); + srsran_rf_set_rx_freq(&rf, nof_rx_antennas, rf_freq); + printf("Set RX freq: %.2f MHz\n", rf_freq / 1000000); + printf("Set RX gain: %.2f dB\n", rf_gain); + float srate = srsran_rf_set_rx_srate(&rf, rf_rate); + if (srate != rf_rate) { + srate = srsran_rf_set_rx_srate(&rf, rf_rate); + if (srate != rf_rate) { + ERROR("Error setting samplign frequency %.2f MHz", rf_rate * 1e-6); + exit(-1); + } + } + + printf("Correctly RX rate: %.2f MHz\n", srate * 1e-6); + srsran_rf_start_rx_stream(&rf, false); + + while ((sample_count < nof_samples || nof_samples == -1) && keep_running) { + n = srsran_rf_recv_with_time_multi(&rf, (void**)buffer, buflen, true, NULL, NULL); + if (n < 0) { + ERROR("Error receiving samples"); + exit(-1); + } + + srsran_filesink_write_multi(&sink, (void**)buffer, buflen, nof_rx_antennas); + sample_count += buflen; + } + + for (int i = 0; i < nof_rx_antennas; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + + srsran_filesink_free(&sink); + srsran_rf_close(&rf); + + printf("Ok - wrote %d samples\n", sample_count); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/usrp_capture_sync.c b/srsRAN_4G_mirror/lib/examples/usrp_capture_sync.c new file mode 100644 index 0000000..aa961d7 --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/usrp_capture_sync.c @@ -0,0 +1,249 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "srsran/phy/rf/rf.h" +#include "srsran/srsran.h" + +static bool keep_running = true; +char* output_file_name = NULL; +static char rf_devname[64] = ""; +static char rf_args[64] = "auto"; +float rf_gain = 60.0, rf_freq = -1.0; +int nof_prb = 6; +int nof_subframes = -1; +int N_id_2 = -1; +uint32_t nof_rx_antennas = 1; +bool use_standard_lte_rates = false; +srsran_ue_sync_mode_t sync_mode = SYNC_MODE_PSS; + +void int_handler(int dummy) +{ + keep_running = false; +} + +void usage(char* prog) +{ + printf("Usage: %s [agrnv] -l N_id_2 -f rx_frequency_hz -o output_file\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-d RF devicename [Default %s]\n", rf_devname); + printf("\t-e use_standard_lte_rates [Default %i]\n", use_standard_lte_rates); + printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); + printf("\t-p nof_prb [Default %d]\n", nof_prb); + printf("\t-n nof_subframes [Default %d]\n", nof_subframes); + printf("\t-m Use GPS sync mode [Default %s]\n", sync_mode == SYNC_MODE_PSS ? "false" : "true"); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); + printf("\t-v verbose\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "adegpnmvfolA")) != -1) { + switch (opt) { + case 'o': + output_file_name = argv[optind]; + break; + case 'a': + strncpy(rf_args, argv[optind], 63); + rf_args[63] = '\0'; + break; + case 'd': + strncpy(rf_devname, argv[optind], 63); + rf_devname[63] = '\0'; + break; + case 'e': + use_standard_lte_rates = true; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'p': + nof_prb = (int)strtol(argv[optind], NULL, 10); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'n': + nof_subframes = (int)strtol(argv[optind], NULL, 10); + break; + case 'm': + sync_mode = SYNC_MODE_GNSS; + break; + case 'l': + N_id_2 = (int)strtol(argv[optind], NULL, 10); + break; + case 'A': + nof_rx_antennas = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (&rf_freq < 0 || N_id_2 == -1 || output_file_name == NULL) { + usage(argv[0]); + exit(-1); + } +} + +int srsran_rf_recv_wrapper(void* h, cf_t* data[SRSRAN_MAX_PORTS], uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + void* ptr[SRSRAN_MAX_PORTS]; + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + ptr[i] = data[i]; + } + return srsran_rf_recv_with_time_multi(h, ptr, nsamples, true, &t->full_secs, &t->frac_secs); +} + +int main(int argc, char** argv) +{ + cf_t* buffer[SRSRAN_MAX_CHANNELS] = {NULL}; + int n = 0; + srsran_rf_t rf = {}; + srsran_filesink_t sink = {}; + srsran_ue_sync_t ue_sync = {}; + srsran_cell_t cell = {}; + + signal(SIGINT, int_handler); + + parse_args(argc, argv); + + srsran_use_standard_symbol_size(use_standard_lte_rates); + + srsran_filesink_init(&sink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN); + + printf("Opening RF device...\n"); + if (srsran_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { + ERROR("Error opening rf"); + exit(-1); + } + + uint32_t max_num_samples = 3 * SRSRAN_SF_LEN_MAX; + for (int i = 0; i < nof_rx_antennas; i++) { + buffer[i] = srsran_vec_cf_malloc(max_num_samples); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + + srsran_rf_set_rx_gain(&rf, rf_gain); + printf("Set RX freq: %.6f MHz\n", srsran_rf_set_rx_freq(&rf, nof_rx_antennas, rf_freq) / 1000000); + printf("Set RX gain: %.1f dB\n", srsran_rf_get_rx_gain(&rf)); + int srate = srsran_sampling_freq_hz(nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1000000); + float srate_rf = srsran_rf_set_rx_srate(&rf, (double)srate); + if (srate_rf != srate) { + ERROR("Could not set sampling rate"); + exit(-1); + } + } else { + ERROR("Invalid number of PRB %d", nof_prb); + exit(-1); + } + srsran_rf_start_rx_stream(&rf, false); + + cell.cp = SRSRAN_CP_NORM; + cell.id = N_id_2; + cell.nof_prb = nof_prb; + cell.nof_ports = 1; + + if (srsran_ue_sync_init_multi_decim_mode( + &ue_sync, cell.nof_prb, cell.id == 1000, srsran_rf_recv_wrapper, nof_rx_antennas, (void*)&rf, 1, sync_mode)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + if (srsran_ue_sync_set_cell(&ue_sync, cell)) { + ERROR("Error initiating ue_sync"); + exit(-1); + } + + uint32_t subframe_count = 0; + bool start_capture = false; + bool stop_capture = false; + srsran_timestamp_t ts_rx_start = {}; + while ((subframe_count < nof_subframes || nof_subframes == -1) && !stop_capture) { + n = srsran_ue_sync_zerocopy(&ue_sync, buffer, max_num_samples); + if (n < 0) { + ERROR("Error receiving samples"); + exit(-1); + } + if (n == 1) { + if (!start_capture) { + if (srsran_ue_sync_get_sfidx(&ue_sync) == 9) { + start_capture = true; + } + } else { + printf("Writing to file %6d subframes...\r", subframe_count); + srsran_filesink_write_multi(&sink, (void**)buffer, SRSRAN_SF_LEN_PRB(nof_prb), nof_rx_antennas); + + // store time stamp of first subframe + if (subframe_count == 0) { + srsran_ue_sync_get_last_timestamp(&ue_sync, &ts_rx_start); + } + subframe_count++; + } + } + if (!keep_running) { + if (!start_capture || (start_capture && srsran_ue_sync_get_sfidx(&ue_sync) == 9)) { + stop_capture = true; + } + } + } + + srsran_filesink_free(&sink); + srsran_rf_close(&rf); + srsran_ue_sync_free(&ue_sync); + + for (int i = 0; i < nof_rx_antennas; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + + printf("\nOk - wrote %d subframes\n", subframe_count); + + srsran_ue_sync_set_tti_from_timestamp(&ue_sync, &ts_rx_start); + printf("Start of capture at %ld+%.3f. TTI=%d.%d\n", + ts_rx_start.full_secs, + ts_rx_start.frac_secs, + srsran_ue_sync_get_sfn(&ue_sync), + srsran_ue_sync_get_sfidx(&ue_sync)); + + return SRSRAN_SUCCESS; +} diff --git a/srsRAN_4G_mirror/lib/examples/usrp_capture_sync_nbiot.c b/srsRAN_4G_mirror/lib/examples/usrp_capture_sync_nbiot.c new file mode 100644 index 0000000..cd5d49a --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/usrp_capture_sync_nbiot.c @@ -0,0 +1,192 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/phy/io/filesink.h" +#include "srsran/phy/rf/rf.h" +#include "srsran/phy/ue/ue_mib_nbiot.h" +#include "srsran/phy/ue/ue_sync_nbiot.h" +#include "srsran/phy/utils/debug.h" + +static bool keep_running = true; +char* output_file_name = NULL; +char* rf_args = ""; +float rf_gain = 60.0, rf_freq = -1.0; +int nof_prb = 6; +int nof_subframes = -1; + +void int_handler(int dummy) +{ + keep_running = false; +} + +void usage(char* prog) +{ + printf("Usage: %s [agrtnv] -f rx_frequency_hz -o output_file\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); + printf("\t-n nof_subframes [Default %d]\n", nof_subframes); + printf("\t-v verbose\n"); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "agnvfto")) != -1) { + switch (opt) { + case 'o': + output_file_name = argv[optind]; + break; + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'n': + nof_subframes = (int)strtol(argv[optind], NULL, 10); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (&rf_freq < 0 || output_file_name == NULL) { + usage(argv[0]); + exit(-1); + } +} + +int srsran_rf_recv_wrapper(void* h, void* data, uint32_t nsamples, srsran_timestamp_t* t) +{ + DEBUG(" ---- Receive %d samples ----", nsamples); + return srsran_rf_recv(h, data, nsamples, 1); +} + +int main(int argc, char** argv) +{ + signal(SIGINT, int_handler); + + parse_args(argc, argv); + + srsran_filesink_t sink; + srsran_filesink_init(&sink, output_file_name, SRSRAN_COMPLEX_FLOAT_BIN); + + printf("Opening RF device...\n"); + srsran_rf_t rf; + if (srsran_rf_open(&rf, rf_args)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + + srsran_rf_set_rx_gain(&rf, rf_gain); + printf("Set RX freq: %.6f MHz\n", srsran_rf_set_rx_freq(&rf, 0, rf_freq) / 1000000); + printf("Set RX gain: %.1f dB\n", srsran_rf_get_rx_gain(&rf)); + int srate = srsran_sampling_freq_hz(nof_prb); + if (srate != -1) { + printf("Setting sampling rate %.2f MHz\n", (float)srate / 1e6); + double srate_rf = srsran_rf_set_rx_srate(&rf, srate); + printf("Actual sampling rate %.2f MHz\n", srate_rf / 1e6); + // We don't check the result rate with requested rate + } else { + fprintf(stderr, "Invalid number of PRB %d\n", nof_prb); + exit(-1); + } + srsran_rf_start_rx_stream(&rf, false); + + srsran_nbiot_cell_t cell = {}; + cell.base.nof_prb = nof_prb; + cell.base.nof_ports = 1; + + cf_t* buff_ptrs[SRSRAN_MAX_PORTS] = {NULL, NULL, NULL, NULL}; + buff_ptrs[0] = srsran_vec_cf_malloc(SRSRAN_SF_LEN_PRB_NBIOT * 10); + + srsran_nbiot_ue_sync_t ue_sync; + if (srsran_ue_sync_nbiot_init(&ue_sync, cell, srsran_rf_recv_wrapper, (void*)&rf)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + + int32_t nof_warmup_subframes = 1024; + uint32_t subframe_count = 0; + bool start_capture = false; + bool stop_capture = false; + while ((subframe_count < nof_subframes || nof_subframes == -1) && !stop_capture) { + int n = srsran_ue_sync_nbiot_zerocopy_multi(&ue_sync, buff_ptrs); + if (n < 0) { + fprintf(stderr, "Error receiving samples\n"); + exit(-1); + } + + if (n == 1) { + if (!start_capture) { + if (nof_warmup_subframes <= 0) { + if (srsran_ue_sync_nbiot_get_sfidx(&ue_sync) == 9) { + printf("Starting capture ..\n"); + start_capture = true; + } + } + nof_warmup_subframes--; + } else { + printf("Writing subframe %d (%d/%d) to file (cfo=%6.2f kHz)\n", + srsran_ue_sync_nbiot_get_sfidx(&ue_sync), + subframe_count, + nof_subframes, + srsran_ue_sync_nbiot_get_cfo(&ue_sync) / 1000); + srsran_filesink_write(&sink, buff_ptrs[0], SRSRAN_SF_LEN_PRB(nof_prb)); + subframe_count++; + } + } + if (!keep_running) { + if (!start_capture || (start_capture && srsran_ue_sync_nbiot_get_sfidx(&ue_sync) == 9)) { + printf("Stopping capture ..\n"); + stop_capture = true; + } + } + } + + srsran_filesink_free(&sink); + srsran_rf_close(&rf); + srsran_ue_sync_nbiot_free(&ue_sync); + + printf("Ok - wrote %d subframes\n", subframe_count); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/usrp_txrx.c b/srsRAN_4G_mirror/lib/examples/usrp_txrx.c new file mode 100644 index 0000000..a41fa8e --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/usrp_txrx.c @@ -0,0 +1,194 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/phy/rf/rf.h" +#include "srsran/srsran.h" + +uint32_t nof_prb = 25; +uint32_t nof_frames = 20; + +int time_adv_samples = 0; +float tone_offset_hz = 1e6; +float rf_rx_gain = 40, srsran_rf_tx_gain = 40, rf_freq = 2.4e9; +char* rf_args = ""; +char* output_filename = NULL; +char* input_filename = NULL; + +void usage(char* prog) +{ + printf("Usage: %s -o [rx_signal_file]\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-f RF TX/RX frequency [Default %.2f MHz]\n", rf_freq / 1e6); + printf("\t-g RF RX gain [Default %.1f dB]\n", rf_rx_gain); + printf("\t-G RF TX gain [Default %.1f dB]\n", srsran_rf_tx_gain); + printf("\t-t Single tone offset (Hz) [Default %f]\n", tone_offset_hz); + printf("\t-T Time advance samples [Default %d]\n", time_adv_samples); + printf("\t-i File name to read signal from [Default single tone]\n"); + printf("\t-p Number of UL RB [Default %d]\n", nof_prb); +} + +void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "ioafgGptT")) != -1) { + switch (opt) { + case 'a': + rf_args = argv[optind]; + break; + case 'o': + output_filename = argv[optind]; + break; + case 'i': + input_filename = argv[optind]; + break; + case 't': + tone_offset_hz = strtof(argv[optind], NULL); + break; + case 'T': + time_adv_samples = (int)strtol(argv[optind], NULL, 10); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'g': + rf_rx_gain = strtof(argv[optind], NULL); + break; + case 'G': + srsran_rf_tx_gain = strtof(argv[optind], NULL); + break; + case 'p': + nof_prb = (uint32_t)strtol(argv[optind], NULL, 10); + if (!srsran_nofprb_isvalid(nof_prb)) { + ERROR("Invalid number of UL RB %d", nof_prb); + exit(-1); + } + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!output_filename) { + usage(argv[0]); + exit(-1); + } + if (time_adv_samples < 0) { + printf("Time advance must be positive\n"); + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char** argv) +{ + parse_args(argc, argv); + + uint32_t flen = srsran_sampling_freq_hz(nof_prb) / 1000; + + cf_t* rx_buffer = srsran_vec_cf_malloc(flen * nof_frames); + if (!rx_buffer) { + perror("malloc"); + exit(-1); + } + + cf_t* tx_buffer = srsran_vec_cf_malloc((flen + time_adv_samples)); + if (!tx_buffer) { + perror("malloc"); + exit(-1); + } + srsran_vec_cf_zero(tx_buffer, flen + time_adv_samples); + + cf_t* zeros = srsran_vec_cf_malloc(flen); + if (!zeros) { + perror("calloc"); + exit(-1); + } + srsran_vec_cf_zero(zeros, flen); + + float time_adv_sec = (float)time_adv_samples / srsran_sampling_freq_hz(nof_prb); + + // Send through RF + srsran_rf_t rf; + printf("Opening RF device...\n"); + if (srsran_rf_open(&rf, rf_args)) { + ERROR("Error opening rf"); + exit(-1); + } + + int srate = srsran_sampling_freq_hz(nof_prb); + srsran_rf_set_rx_srate(&rf, (double)srate); + srsran_rf_set_tx_srate(&rf, (double)srate); + + srsran_rf_set_rx_gain(&rf, rf_rx_gain); + srsran_rf_set_tx_gain(&rf, srsran_rf_tx_gain); + srsran_rf_set_rx_freq(&rf, 0, rf_freq); + + printf("Subframe len: %d samples\n", flen); + printf("Time advance: %f us\n", time_adv_sec * 1e6); + printf("Set TX/RX rate: %.2f MHz\n", (float)srate / 1000000); + printf("Set RX gain: %.1f dB\n", rf_rx_gain); + printf("Set TX gain: %.1f dB\n", srsran_rf_tx_gain); + printf("Set TX/RX freq: %.2f MHz\n", rf_freq / 1000000); + srsran_rf_set_tx_freq(&rf, 0, rf_freq); + + sleep(1); + + if (input_filename) { + srsran_vec_load_file(input_filename, &tx_buffer[time_adv_samples], flen * sizeof(cf_t)); + } else { + for (int i = 0; i < flen - time_adv_samples; i++) { + tx_buffer[i + time_adv_samples] = 0.3 * cexpf(_Complex_I * 2 * M_PI * tone_offset_hz * ((float)i / (float)srate)); + } + srsran_vec_save_file("srsran_rf_txrx_tone", tx_buffer, flen * sizeof(cf_t)); + } + + srsran_timestamp_t tstamp; + + srsran_rf_start_rx_stream(&rf, false); + uint32_t nframe = 0; + + while (nframe < nof_frames) { + printf("Rx subframe %d\n", nframe); + srsran_rf_recv_with_time(&rf, &rx_buffer[flen * nframe], flen, true, &tstamp.full_secs, &tstamp.frac_secs); + nframe++; + if (nframe == 9) { + srsran_timestamp_add(&tstamp, 0, 2e-3 - time_adv_sec); + srsran_rf_send_timed2(&rf, tx_buffer, flen + time_adv_samples, tstamp.full_secs, tstamp.frac_secs, true, true); + printf("Transmitting Signal\n"); + } + } + + srsran_vec_save_file(output_filename, &rx_buffer[10 * flen], flen * sizeof(cf_t)); + + free(tx_buffer); + free(rx_buffer); + + printf("Done\n"); + exit(0); +} diff --git a/srsRAN_4G_mirror/lib/examples/zmq_remote_rx.c b/srsRAN_4G_mirror/lib/examples/zmq_remote_rx.c new file mode 100644 index 0000000..a36dc2c --- /dev/null +++ b/srsRAN_4G_mirror/lib/examples/zmq_remote_rx.c @@ -0,0 +1,264 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "srsran/phy/rf/rf.h" +#include "srsran/srsran.h" + +static bool keep_running = true; +static uint32_t nof_rx_antennas = 1; +static const uint32_t max_rx_antennas = 1; + +static void int_handler(int dummy); +static void usage(char* prog); +static void parse_args(int argc, char** argv); +static int init_radio(uint32_t* buf_len); +static int rx_radio(void** buffer, uint32_t buff_len); +static void close_radio(); + +/* Example function to initialize ZMQ socket */ +static void* zmq_ctx = NULL; +static void* zmq_sock = NULL; +static const char* zmq_args = "tcp://*:5550"; +static int init_zmq() +{ + zmq_ctx = zmq_ctx_new(); + + // Create socket + zmq_sock = zmq_socket(zmq_ctx, ZMQ_PUB); + if (!zmq_sock) { + fprintf(stderr, "Error: creating transmitter socket\n"); + return -1; + } + + // The transmitter starts first and creates the socket + if (zmq_bind(zmq_sock, zmq_args)) { + fprintf(stderr, "Error: connecting transmitter socket: %s\n", zmq_strerror(zmq_errno())); + return -1; + } + return 0; +} + +/* Example function to write samples to ZMQ socket */ +static int tx_zmq(void** buffer, uint32_t buffer_len) +{ + // wait for request + uint8_t dummy; + zmq_recv(zmq_sock, &dummy, sizeof(dummy), 0); + return zmq_send(zmq_sock, buffer[0], buffer_len, 0); +} + +int main(int argc, char** argv) +{ + void* buffer[max_rx_antennas]; + int n = 0; + uint32_t buflen = 0; // in samples + uint32_t sample_size = 8; + + // Sets signal handlers + signal(SIGINT, int_handler); + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigset, NULL); + + // Parse args + parse_args(argc, argv); + + // Initializes ZMQ + if (init_zmq()) { + ERROR("Initializing ZMQ"); + exit(-1); + } + + if (init_radio(&buflen)) { + ERROR("Initializing Radio"); + exit(-1); + } + + // Initializes memory for input buffer + bzero(buffer, sizeof(void*) * max_rx_antennas); + for (int i = 0; i < nof_rx_antennas; i++) { + buffer[i] = srsran_vec_cf_malloc(buflen); + if (!buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + printf("Streaming samples...\n"); + uint32_t print_cnt = 0; + while (keep_running) { + n = rx_radio(buffer, buflen); + if (n < 0) { + ERROR("Error receiving samples"); + exit(-1); + } + if (get_srsran_verbose_level() == SRSRAN_VERBOSE_INFO) { + printf("Received %d samples from radio\n", n); + } + + n = tx_zmq((void**)buffer, n * sample_size); + + if (n == -1) { + print_cnt++; + if (print_cnt == 1000) { + printf("ZMQ socket not connected\n"); + print_cnt = 0; + } + } else { + if (get_srsran_verbose_level() == SRSRAN_VERBOSE_INFO) { + printf("Transmitted %d bytes to ZMQ\n", n); + } + } + } + + // Cleanup memory and close RF device + for (int i = 0; i < nof_rx_antennas; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + close_radio(); + + printf("Exit Ok\n"); + exit(0); +} + +/* Example function to initialize the Radio frontend. In this case, we use srsRAN RF API to open a device, + * which automatically picks UHD, bladeRF, limeSDR, etc. + */ +static srsran_rf_t radio = {}; +static char* rf_args = "fastpath"; +static float rf_gain = 40.0, rf_freq = -1.0, rf_rate = 11.52e6; +static uint32_t rf_recv_frame_size_ms = 1; +static int init_radio(uint32_t* buffer_len) +{ + // Uses srsRAN RF API to open a device, could use other code here + printf("Opening RF device...\n"); + if (srsran_rf_open_multi(&radio, rf_args, nof_rx_antennas)) { + ERROR("Error opening rf"); + return -1; + } + srsran_rf_set_rx_gain(&radio, rf_gain); + srsran_rf_set_rx_freq(&radio, nof_rx_antennas, rf_freq); + + printf("Set RX freq: %.2f MHz\n", rf_freq / 1000000); + printf("Set RX gain: %.2f dB\n", rf_gain); + float srate = srsran_rf_set_rx_srate(&radio, rf_rate); + if (srate != rf_rate) { + ERROR("Error setting samplign frequency %.2f MHz", rf_rate * 1e-6); + return -1; + } + + if (buffer_len) { + *buffer_len = srate * rf_recv_frame_size_ms * 1e-3; + } + + printf("Set RX rate: %.2f MHz\n", srate * 1e-6); + srsran_rf_start_rx_stream(&radio, false); + return 0; +} + +/* Example implementation to receive from Radio frontend. In this case we use srsRAN + */ +static int rx_radio(void** buffer, uint32_t buf_len) +{ + return srsran_rf_recv_with_time_multi(&radio, buffer, buf_len, true, NULL, NULL); +} + +static void close_radio() +{ + srsran_rf_close(&radio); +} + +static void int_handler(int dummy) +{ + keep_running = false; +} + +static void usage(char* prog) +{ + printf("Usage: %s [agrAzv] -f rx_frequency_hz\n", prog); + printf("\t-a RF args [Default %s]\n", rf_args); + printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); + printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate); + printf("\t-m RF receive frame size in ms [Default %d ms]\n", rf_recv_frame_size_ms); + printf("\t-A Number of antennas [Max %d, Default %d]\n", max_rx_antennas, nof_rx_antennas); + printf("\t-z ZMQ args [Default %s]\n", zmq_args); + printf("\t-v srsran_verbose\n"); +} + +static void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "agrfvmzA")) != -1) { + switch (opt) { + case 'a': + rf_args = argv[optind]; + break; + case 'g': + rf_gain = strtof(argv[optind], NULL); + break; + case 'm': + rf_recv_frame_size_ms = strtol(argv[optind], NULL, 10); + break; + case 'r': + rf_rate = strtof(argv[optind], NULL); + break; + case 'f': + rf_freq = strtof(argv[optind], NULL); + break; + case 'v': + increase_srsran_verbose_level(); + break; + case 'z': + zmq_args = argv[optind]; + break; + case 'A': + nof_rx_antennas = strtol(argv[optind], NULL, 10); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (nof_rx_antennas > max_rx_antennas || nof_rx_antennas < 1) { + fprintf(stderr, "Invalid number of antennas\n"); + usage(argv[0]); + exit(-1); + } + if (rf_freq < 0) { + usage(argv[0]); + exit(-1); + } +} diff --git a/srsRAN_4G_mirror/lib/include/CMakeLists.txt b/srsRAN_4G_mirror/lib/include/CMakeLists.txt new file mode 100644 index 0000000..586bda2 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +######################################################################## +# Add subdirectories +######################################################################## +add_subdirectory(srsran) + diff --git a/srsRAN_4G_mirror/lib/include/srsran/CMakeLists.txt b/srsRAN_4G_mirror/lib/include/srsran/CMakeLists.txt new file mode 100644 index 0000000..666ffb9 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN 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 Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/version.h +) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.h + DESTINATION "${INCLUDE_DIR}/srsran" +) diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/accumulators.h b/srsRAN_4G_mirror/lib/include/srsran/adt/accumulators.h new file mode 100644 index 0000000..9cf9d76 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/accumulators.h @@ -0,0 +1,174 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_ACCUMULATORS_H +#define SRSRAN_ACCUMULATORS_H + +#include +#include +#include +#include +#include + +namespace srsran { + +template +struct rolling_average { + void push(T sample) + { + avg_ += (sample - avg_) / (count_ + 1); + ++count_; + } + T value() const { return count_ == 0 ? 0 : avg_; } + uint32_t count() const { return count_; } + void reset() + { + avg_ = 0; + count_ = 0; + } + +private: + T avg_ = 0; + uint32_t count_ = 0; +}; + +template +struct exp_average_fast_start { + exp_average_fast_start(T alpha_val) : exp_average_fast_start(alpha_val, 1.0 / alpha_val) {} + exp_average_fast_start(T alpha_val, uint32_t start_size) : alpha_(alpha_val), start_count_size(start_size) + { + assert(alpha_ < 1); + assert(start_size > 0); + } + void push(T sample) + { + if (count < start_count_size) { + avg_ += (sample - avg_) / (count + 1); + count++; + } else { + avg_ = (1 - alpha_) * avg_ + alpha_ * sample; + } + } + T value() const { return count == 0 ? 0 : avg_; } + T alpha() const { return alpha_; } + bool is_exp_average_mode() const { return count >= start_count_size; } + +private: + T avg_ = 0; + uint32_t count = 0; + uint32_t start_count_size; + T alpha_; +}; + +namespace detail { + +template +struct sliding_window { + sliding_window(uint32_t N, T val = 0) : window(N, val) {} + void push(T sample) + { + window[next_idx++] = sample; + if (next_idx >= window.size()) { + next_idx -= window.size(); + } + } + std::size_t size() const { return window.size(); } + const T& oldest() const { return window[next_idx % size()]; } + T& operator[](std::size_t i) { return window[i]; } + const T& operator[](std::size_t i) const { return window[i]; } + std::vector window; + std::size_t next_idx = 0; +}; + +} // namespace detail + +template +struct sliding_sum : private detail::sliding_window { + using base_t = detail::sliding_window; + using base_t::oldest; + using base_t::push; + using base_t::size; + using base_t::sliding_window; + + T value() const + { + T ret = 0; + for (std::size_t i = 0; i < size(); ++i) { + ret += (*this)[i]; + } + return ret; + } +}; + +template +struct sliding_average { + sliding_average(uint32_t N) : window(N, 0) {} + void push(T sample) { window.push(sample); } + T value() const { return window.value() / window.size(); } + +private: + sliding_sum window; +}; + +template +struct null_sliding_average { + null_sliding_average(uint32_t N) : window(N, null_value()) {} + void push(T sample) { window.push(sample); } + void push_hole() { window.push(null_value()); } + T value() const + { + T ret = 0; + uint32_t count = 0; + for (std::size_t i = 0; i < window.size(); ++i) { + if (window[i] != null_value()) { + ret += window[i]; + count++; + } + } + return (count == 0) ? null_value() : ret / count; + } + static constexpr T null_value() { return std::numeric_limits::max(); } + +private: + detail::sliding_window window; +}; + +template +struct exp_average_irreg_sampling { + // an exp_average has the formula y_n = alpha*x + (1-alpha)*y_n-1 <=> y_n += alpha(x - y_n-1) + // alpha can be thought as 1-exp^{-dt/T} where dt is the sample period and T is the time-constant of a LP filter + // for variable dt, alpha[dt] = 1-exp^{-dt/T} = 1-(exp^{-1/T})^dt = 1 - (1-alpha[1])^dt + exp_average_irreg_sampling(T alpha_, T init_val) : avg_(init_val) + { + assert(alpha_ < 1 and alpha_ > 0 and "Invalid alpha parameter."); + coeff = 1 - alpha_; + } + void push(T sample, uint32_t sample_jump) { avg_ += (1 - pow(coeff, sample_jump)) * (sample - avg_); } + T value() const { return avg_; } + +private: + T avg_ = 0; + T coeff; +}; + +} // namespace srsran + +#endif // SRSRAN_ACCUMULATORS_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_bitset.h b/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_bitset.h new file mode 100644 index 0000000..1926e21 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_bitset.h @@ -0,0 +1,607 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_DYN_BITSET_H +#define SRSRAN_DYN_BITSET_H + +#include "srsran/srslog/bundled/fmt/format.h" +#include "srsran/support/srsran_assert.h" +#include +#include +#include + +namespace srsran { + +constexpr uint32_t ceil_div(uint32_t x, uint32_t y) +{ + return (x + y - 1) / y; +} + +template +Integer mask_msb_zeros(size_t N) +{ + static_assert(std::is_unsigned::value, "T must be unsigned integer"); + return (N == 0) ? static_cast(-1) : (N == sizeof(Integer) * 8U) ? 0 : (static_cast(-1) >> (N)); +} + +template +Integer mask_lsb_ones(size_t N) +{ + return mask_msb_zeros(sizeof(Integer) * 8U - N); +} + +template +Integer mask_msb_ones(size_t N) +{ + return ~mask_msb_zeros(N); +} + +template +Integer mask_lsb_zeros(size_t N) +{ + return ~mask_lsb_ones(N); +} + +namespace detail { + +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1; shift != 0; shift >>= 1) { + Integer tmp = value >> shift; + if (tmp != 0) { + value = tmp; + } else { + ret |= shift; + } + } + return ret; + } + static Integer lsb_count(Integer value) + { + if (value == 0) { + return std::numeric_limits::digits; + } + Integer ret = 0; + for (Integer shift = std::numeric_limits::digits >> 1, mask = std::numeric_limits::max() >> shift; + shift != 0; + shift >>= 1, mask >>= shift) { + if ((value & mask) == 0) { + value >>= shift; + ret |= shift; + } + } + return ret; + } +}; + +#ifdef __GNUC__ // clang and gcc +/// Specializations for unsigned +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clz(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctz(value) : std::numeric_limits::digits; + } +}; + +/// Specializations for unsigned long long +template +struct zerobit_counter { + static Integer msb_count(Integer value) + { + return (value) ? __builtin_clzll(value) : std::numeric_limits::digits; + } + static Integer lsb_count(Integer value) + { + return (value) ? __builtin_ctzll(value) : std::numeric_limits::digits; + } +}; +#endif + +} // namespace detail + +/// uses lsb as zero position +template +Integer find_first_msb_one(Integer value) +{ + return (value) ? (sizeof(Integer) * 8U - 1 - detail::zerobit_counter::msb_count(value)) + : std::numeric_limits::digits; +} + +/// uses lsb as zero position +template +Integer find_first_lsb_one(Integer value) +{ + return detail::zerobit_counter::lsb_count(value); +} + +template +class bounded_bitset +{ + typedef uint64_t word_t; + static const size_t bits_per_word = 8 * sizeof(word_t); + +public: + constexpr bounded_bitset() = default; + + constexpr explicit bounded_bitset(size_t cur_size_) : cur_size(cur_size_) {} + + constexpr size_t max_size() const noexcept { return N; } + + size_t size() const noexcept { return cur_size; } + + void resize(size_t new_size) + { + srsran_assert(new_size <= max_size(), "ERROR: new size=%zd exceeds bitset capacity=%zd", new_size, max_size()); + if (new_size == cur_size) { + return; + } + cur_size = new_size; + sanitize_(); + for (size_t i = nof_words_(); i < max_nof_words_(); ++i) { + buffer[i] = static_cast(0); + } + } + + void set(size_t pos, bool val) + { + assert_within_bounds_(pos, true); + if (val) { + set_(pos); + } else { + reset_(pos); + } + } + + void set(size_t pos) + { + assert_within_bounds_(pos, true); + set_(pos); + } + + void reset(size_t pos) + { + assert_within_bounds_(pos, true); + reset_(pos); + } + + void reset() noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] = static_cast(0); + } + } + + bool test(size_t pos) const + { + assert_within_bounds_(pos, true); + return test_(pos); + } + + bounded_bitset& flip() noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] = ~buffer[i]; + } + sanitize_(); + return *this; + } + + bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) + { + assert_range_bounds_(startpos, endpos); + // NOTE: can be optimized + if (value) { + for (size_t i = startpos; i < endpos; ++i) { + set_(i); + } + } else { + for (size_t i = startpos; i < endpos; ++i) { + reset_(i); + } + } + return *this; + } + + int find_lowest(size_t startpos, size_t endpos, bool value = true) const noexcept + { + assert_range_bounds_(startpos, endpos); + if (startpos == endpos) { + return -1; + } + + if (not reversed) { + return find_first_(startpos, endpos, value); + } + return find_first_reversed_(startpos, endpos, value); + } + + bool all() const noexcept + { + const size_t nw = nof_words_(); + if (nw == 0) { + return true; + } + word_t allset = ~static_cast(0); + for (size_t i = 0; i < nw - 1; i++) { + if (buffer[i] != allset) { + return false; + } + } + return buffer[nw - 1] == (allset >> (nw * bits_per_word - size())); + } + + bool any() const noexcept + { + for (size_t i = 0; i < nof_words_(); ++i) { + if (buffer[i] != static_cast(0)) { + return true; + } + } + return false; + } + + bool any(size_t start, size_t stop) const + { + assert_within_bounds_(start, false); + assert_within_bounds_(stop, false); + // NOTE: can be optimized + for (size_t i = start; i < stop; ++i) { + if (test_(i)) { + return true; + } + } + return false; + } + + bool none() const noexcept { return !any(); } + + size_t count() const noexcept + { + size_t result = 0; + for (size_t i = 0; i < nof_words_(); i++) { + // result += __builtin_popcountl(buffer[i]); + // Note: use an "int" for count triggers popcount optimization if SSE instructions are enabled. + int c = 0; + for (word_t w = buffer[i]; w > 0; c++) { + w &= w - 1; + } + result += c; + } + return result; + } + + bool operator==(const bounded_bitset& other) const noexcept + { + if (size() != other.size()) { + return false; + } + for (uint32_t i = 0; i < nof_words_(); ++i) { + if (buffer[i] != other.buffer[i]) { + return false; + } + } + return true; + } + + bool operator!=(const bounded_bitset& other) const noexcept { return not(*this == other); } + + bounded_bitset& operator|=(const bounded_bitset& other) + { + srsran_assert(other.size() == size(), + "ERROR: operator|= called for bitsets of different sizes (%zd!=%zd)", + size(), + other.size()); + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] |= other.buffer[i]; + } + return *this; + } + + bounded_bitset& operator&=(const bounded_bitset& other) + { + srsran_assert(other.size() == size(), + "ERROR: operator&= called for bitsets of different sizes (%zd!=%zd)", + size(), + other.size()); + for (size_t i = 0; i < nof_words_(); ++i) { + buffer[i] &= other.buffer[i]; + } + return *this; + } + + bounded_bitset operator~() const noexcept + { + bounded_bitset ret(*this); + ret.flip(); + return ret; + } + + template + OutputIt to_string(OutputIt&& mem_buffer) const + { + if (size() == 0) { + return mem_buffer; + } + + std::string s; + s.assign(size(), '0'); + if (not reversed) { + for (size_t i = size(); i > 0; --i) { + fmt::format_to(mem_buffer, "{}", test(i - 1) ? '1' : '0'); + } + } else { + for (size_t i = 0; i < size(); ++i) { + fmt::format_to(mem_buffer, "{}", test(i) ? '1' : '0'); + } + } + return mem_buffer; + } + + uint64_t to_uint64() const + { + srsran_assert(nof_words_() == 1, "ERROR: cannot convert bitset of size=%zd to uint64_t", size()); + return get_word_(0); + } + + void from_uint64(uint64_t v) + { + srsran_assert(nof_words_() == 1, "ERROR: cannot convert bitset of size=%zd to uint64_t", size()); + srsran_assert( + v < (1U << size()), "ERROR: Provided mask=0x%" PRIx64 " does not fit in bitset of size=%zd", v, size()); + buffer[0] = v; + } + + template + OutputIt to_hex(OutputIt&& mem_buffer) const noexcept + { + if (size() == 0) { + return mem_buffer; + } + // first word may not print 16 hex digits + int i = nof_words_() - 1; + size_t rem_symbols = ceil_div((size() - (size() / bits_per_word) * bits_per_word), 4U); + fmt::format_to(mem_buffer, "{:0>{}x}", buffer[i], rem_symbols); + // remaining words will occupy 16 hex digits + for (--i; i >= 0; --i) { + fmt::format_to(mem_buffer, "{:0>16x}", buffer[i]); + } + return mem_buffer; + } + +private: + word_t buffer[(N - 1) / bits_per_word + 1] = {0}; + size_t cur_size = 0; + + void sanitize_() + { + size_t n = size() % bits_per_word; + size_t nwords = nof_words_(); + if (n != 0 and nwords > 0) { + buffer[nwords - 1] &= ~((~static_cast(0)) << n); + } + } + + size_t get_bitidx_(size_t bitpos) const noexcept { return reversed ? size() - 1 - bitpos : bitpos; } + + bool test_(size_t bitpos) const noexcept + { + bitpos = get_bitidx_(bitpos); + return ((get_word_(bitpos) & maskbit(bitpos)) != static_cast(0)); + } + + void set_(size_t bitpos) noexcept + { + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) |= maskbit(bitpos); + } + + void reset_(size_t bitpos) noexcept + { + bitpos = get_bitidx_(bitpos); + get_word_(bitpos) &= ~(maskbit(bitpos)); + } + + size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } + + word_t& get_word_(size_t bitidx) noexcept { return buffer[bitidx / bits_per_word]; } + + const word_t& get_word_(size_t bitidx) const { return buffer[bitidx / bits_per_word]; } + + size_t word_idx_(size_t pos) const { return pos / bits_per_word; } + + void assert_within_bounds_(size_t pos, bool strict) const noexcept + { + srsran_assert(pos < size() or (not strict and pos == size()), + "ERROR: index=%zd is out-of-bounds for bitset of size=%zd", + pos, + size()); + } + + void assert_range_bounds_(size_t startpos, size_t endpos) const noexcept + { + srsran_assert(startpos <= endpos and endpos <= size(), + "ERROR: range [%zd, %zd) out-of-bounds for bitsize of size=%zd", + startpos, + endpos, + size()); + } + + static word_t maskbit(size_t pos) noexcept { return (static_cast(1)) << (pos % bits_per_word); } + + static size_t max_nof_words_() noexcept { return (N - 1) / bits_per_word + 1; } + + int find_last_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = lastword; i != startpos - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= (reversed) ? mask_msb_zeros(offset) : mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= (reversed) ? mask_msb_ones(offset + 1) : mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_msb_one(w)); + } + } + return -1; + } + + int find_first_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = startword; i <= lastword; ++i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + find_first_lsb_one(w)); + } + } + return -1; + } + + int find_first_reversed_(size_t startpos, size_t endpos, bool value) const noexcept + { + size_t startbitpos = get_bitidx_(startpos), lastbitpos = get_bitidx_(endpos - 1); + size_t startword = startbitpos / bits_per_word; + size_t lastword = lastbitpos / bits_per_word; + + for (size_t i = startword; i != lastword - 1; --i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startbitpos % bits_per_word; + w &= mask_lsb_ones(offset + 1); + } + if (i == lastword) { + size_t offset = lastbitpos % bits_per_word; + w &= mask_lsb_zeros(offset); + } + if (w != 0) { + word_t pos = find_first_msb_one(w); + return static_cast(size() - 1 - (pos + i * bits_per_word)); + } + } + return -1; + } +}; + +template +inline bounded_bitset operator&(const bounded_bitset& lhs, + const bounded_bitset& rhs) noexcept +{ + bounded_bitset res(lhs); + res &= rhs; + return res; +} + +template +inline bounded_bitset operator|(const bounded_bitset& lhs, + const bounded_bitset& rhs) noexcept +{ + bounded_bitset res(lhs); + res |= rhs; + return res; +} + +template +inline bounded_bitset fliplr(const bounded_bitset& other) noexcept +{ + bounded_bitset ret(other.size()); + for (uint32_t i = 0; i < ret.size(); ++i) { + if (other.test(i)) { + ret.set(ret.size() - 1 - i); + } + } + return ret; +} + +} // namespace srsran + +namespace fmt { +/// Custom formatter for bounded_bitset +template +struct formatter > { + enum { hexadecimal, binary } mode = binary; + + template + auto parse(ParseContext& ctx) -> decltype(ctx.begin()) + { + auto it = ctx.begin(); + while (it != ctx.end() and *it != '}') { + if (*it == 'x') { + mode = hexadecimal; + } + ++it; + } + + return it; + } + + template + auto format(const srsran::bounded_bitset& s, FormatContext& ctx) + -> decltype(std::declval().out()) + { + if (mode == hexadecimal) { + return s.template to_hex(ctx.out()); + } + return s.template to_string(ctx.out()); + } +}; +} // namespace fmt + +#endif // SRSRAN_DYN_BITSET_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_vector.h b/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_vector.h new file mode 100644 index 0000000..c543445 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/bounded_vector.h @@ -0,0 +1,249 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_BOUNDED_VECTOR_H +#define SRSRAN_BOUNDED_VECTOR_H + +#include "srsran/adt/detail/type_storage.h" +#include "srsran/support/srsran_assert.h" +#include +#include +#include + +namespace srsran { + +template +class bounded_vector +{ +public: + using iterator = T*; + using const_iterator = const T*; + using size_type = std::size_t; + using value_type = T; + + bounded_vector() = default; + explicit bounded_vector(size_type N) { append(N); } + bounded_vector(size_type N, const T& val) { append(N, val); } + bounded_vector(const bounded_vector& other) { append(other.begin(), other.end()); } + bounded_vector(bounded_vector&& other) noexcept + { + static_assert(std::is_move_constructible::value, "T must be move-constructible"); + std::uninitialized_copy(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), end()); + size_ = other.size(); + other.clear(); + } + bounded_vector(std::initializer_list init) { append(init.begin(), init.end()); } + bounded_vector(const_iterator it_begin, const_iterator it_end) { append(it_begin, it_end); } + ~bounded_vector() { destroy(begin(), end()); } + bounded_vector& operator=(const bounded_vector& other) + { + if (this == &other) { + return *this; + } + assign(other.begin(), other.end()); + return *this; + } + bounded_vector& operator=(bounded_vector&& other) noexcept + { + if (this == &other) { + return *this; + } + size_t min_common_size = std::min(other.size(), size()); + if (min_common_size > 0) { + // move already constructed elements + auto it = std::move(other.begin(), other.begin() + min_common_size, begin()); + destroy(it, end()); + } else { + clear(); + } + // append the rest + std::uninitialized_copy( + std::make_move_iterator(other.begin() + min_common_size), std::make_move_iterator(other.end()), end()); + size_ = other.size(); + other.clear(); + return *this; + } + + void assign(size_type nof_elems, const T& value) + { + clear(); + append(nof_elems, value); + } + void assign(const_iterator it_start, const_iterator it_end) + { + clear(); + append(it_start, it_end); + } + void assign(std::initializer_list ilist) { assign(ilist.begin(), ilist.end()); } + + // Element access + T& operator[](std::size_t i) + { + srsran_assert(i < size_, "Array index is out of bounds."); + return buffer[i].get(); + } + const T& operator[](std::size_t i) const + { + srsran_assert(i < size_, "Array index is out of bounds."); + return buffer[i].get(); + } + T& back() + { + srsran_assert(size_ > 0, "Trying to get back of empty array."); + return *(begin() + size_ - 1); + } + const T& back() const + { + srsran_assert(size_ > 0, "Trying to get back of empty array."); + return *(begin() + size_ - 1); + } + T& front() { return (*this)[0]; } + const T& front() const { return (*this)[0]; } + T* data() { return reinterpret_cast(buffer.data()); } + const T* data() const { return reinterpret_cast(buffer.data()); } + + // Iterators + iterator begin() { return data(); } + iterator end() { return begin() + size_; } + const_iterator begin() const { return data(); } + const_iterator end() const { return begin() + size_; } + + // Capacity + bool empty() const { return size_ == 0; } + std::size_t size() const { return size_; } + std::size_t capacity() const { return MAX_N; } + bool full() const { return size_ == MAX_N; } + + // modifiers + void clear() + { + destroy(begin(), end()); + size_ = 0; + } + iterator erase(iterator pos) + { + srsran_assert(pos >= this->begin(), "Iterator to erase is out of bounds."); + srsran_assert(pos < this->end(), "Erasing at past-the-end iterator."); + iterator ret = pos; + std::move(pos + 1, end(), pos); + pop_back(); + return ret; + } + iterator erase(iterator it_start, iterator it_end) + { + srsran_assert(it_start >= begin(), "Range to erase is out of bounds."); + srsran_assert(it_start <= it_end, "Trying to erase invalid range."); + srsran_assert(it_end <= end(), "Trying to erase past the end."); + + iterator ret = it_start; + // Shift all elts down. + iterator new_end = std::move(it_end, end(), it_start); + destroy(new_end, end()); + size_ = new_end - begin(); + return ret; + } + void push_back(const T& value) + { + static_assert(std::is_copy_constructible::value, "T must be copy-constructible"); + size_++; + srsran_assert(size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + new (&back()) T(value); + } + void push_back(T&& value) + { + static_assert(std::is_move_constructible::value, "T must be move-constructible"); + size_++; + srsran_assert(size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + new (&back()) T(std::move(value)); + } + template + void emplace_back(Args&&... args) + { + static_assert(std::is_constructible::value, "Passed arguments to emplace_back are invalid"); + size_++; + srsran_assert(size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + new (&back()) T(std::forward(args)...); + } + void pop_back() + { + srsran_assert(size_ > 0, "Trying to erase element from empty vector."); + back().~T(); + size_--; + } + void resize(size_type count) + { + static_assert(std::is_default_constructible::value, "T must be default constructible"); + resize(count, T()); + } + void resize(size_type count, const T& value) + { + static_assert(std::is_copy_constructible::value, "T must be copy constructible"); + if (size_ > count) { + destroy(begin() + count, end()); + size_ = count; + } else if (size_ < count) { + append(count - size_, value); + } + } + + bool operator==(const bounded_vector& other) const + { + return other.size() == size() and std::equal(begin(), end(), other.begin()); + } + bool operator!=(const bounded_vector& other) const { return not(*this == other); } + +private: + void destroy(iterator it_start, iterator it_end) + { + for (auto it = it_start; it != it_end; ++it) { + it->~T(); + } + } + void append(const_iterator it_begin, const_iterator it_end) + { + size_type N = std::distance(it_begin, it_end); + srsran_assert(N + size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + std::uninitialized_copy(it_begin, it_end, end()); + size_ += N; + } + void append(size_type N, const T& element) + { + static_assert(std::is_copy_constructible::value, "T must be copy-constructible"); + srsran_assert(N + size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + std::uninitialized_fill_n(end(), N, element); + size_ += N; + } + void append(size_type N) + { + static_assert(std::is_default_constructible::value, "T must be default-constructible"); + srsran_assert(N + size_ <= MAX_N, "bounded vector maximum size=%zd was exceeded", MAX_N); + for (size_type i = size_; i < size_ + N; ++i) { + buffer[i].emplace(); + } + size_ += N; + } + + std::size_t size_ = 0; + std::array, MAX_N> buffer; +}; +} // namespace srsran + +#endif // SRSRAN_BOUNDED_VECTOR_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/choice_type.h b/srsRAN_4G_mirror/lib/include/srsran/adt/choice_type.h new file mode 100644 index 0000000..3ee27d4 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/choice_type.h @@ -0,0 +1,245 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srsran/adt/detail/type_utils.h" + +#ifndef SRSRAN_CHOICE_TYPE_H +#define SRSRAN_CHOICE_TYPE_H + +namespace srsran { + +//! Compute maximum at compile time +template +struct static_max; +template +struct static_max { + static const std::size_t value = arg; +}; +template +struct static_max { + static const std::size_t value = + arg1 >= arg2 ? static_max::value : static_max::value; +}; + +namespace choice_details { + +//! Holds one of the Args types +template +struct choice_storage_t { + static const std::size_t max_size = MaxSize; + static const std::size_t max_align = MaxAlign; + using buffer_t = typename std::aligned_storage::type; + buffer_t buffer; + + void* get_buffer() { return &buffer; } + + template + T& get_unchecked() + { + return *reinterpret_cast(&buffer); + } + + template + const T& get_unchecked() const + { + return *reinterpret_cast(&buffer); + } + + template + void destroy_unchecked() + { + get_unchecked().~U(); + }; +}; + +/************************* + * Tagged Union Helpers + ************************/ + +template +struct CopyCtorVisitor { + explicit CopyCtorVisitor(C* c_) : c(c_) {} + template + void operator()(const T& t) + { + c->construct_unchecked(t); + } + C* c; +}; + +template +struct MoveCtorVisitor { + explicit MoveCtorVisitor(C* c_) : c(c_) {} + template + void operator()(T&& t) + { + c->construct_unchecked(std::move(t)); + } + C* c; +}; + +template +struct DtorUncheckVisitor { + explicit DtorUncheckVisitor(C* c_) : c(c_) {} + template + void operator()(T& t) + { + c->template destroy_unchecked(); + } + C* c; +}; + +template +struct tagged_union_t; + +template +struct tagged_union_t + : private choice_storage_t::value, static_max::value> { + using base_t = choice_storage_t::value, static_max::value>; + using buffer_t = typename base_t::buffer_t; + using this_type = tagged_union_t; + + std::size_t type_id; + + using base_t::destroy_unchecked; + using base_t::get_buffer; + using base_t::get_unchecked; + + template + void construct_emplace_unchecked(Args2&&... args) + { + using U2 = typename std::decay::type; + static_assert(type_list_contains(), + "The provided type to ctor is not part of the list of possible types"); + type_id = get_type_index(); + new (get_buffer()) U2(std::forward(args)...); + } + + template + void construct_unchecked(U&& u) + { + using U2 = typename std::decay::type; + static_assert(type_list_contains(), + "The provided type to ctor is not part of the list of possible types"); + type_id = get_type_index(); + new (get_buffer()) U2(std::forward(u)); + } + + void copy_unchecked(const this_type& other) { visit(CopyCtorVisitor{this}, other); } + + void move_unchecked(this_type&& other) { visit(MoveCtorVisitor{this}, other); } + + void dtor_unchecked() { visit(choice_details::DtorUncheckVisitor{this}, *this); } + + size_t get_type_idx() const { return type_id; } + + template + bool is() const + { + return get_type_index() == type_id; + } + + template + constexpr static bool can_hold_type() + { + return type_list_contains(); + } +}; + +} // namespace choice_details + +template +class choice_t : private choice_details::tagged_union_t +{ + using base_t = choice_details::tagged_union_t; + +public: + using default_type = typename get_index_type<0, Args...>::type; + //! Useful metafunction + template + using enable_if_can_hold = + typename std::enable_if::type>()>::type; + template + using disable_if_can_hold = + typename std::enable_if::type>()>::type; + + using base_t::can_hold_type; + using base_t::get_unchecked; + using base_t::is; + + template ::value>::type> + explicit choice_t(Args2&&... args) noexcept + { + base_t::template construct_emplace_unchecked(std::forward(args)...); + } + + choice_t(const choice_t& other) noexcept { base_t::copy_unchecked(other); } + + choice_t(choice_t&& other) noexcept { base_t::move_unchecked(std::move(other)); } + + template > + choice_t(U&& u) noexcept + { + base_t::construct_unchecked(std::forward(u)); + } + + ~choice_t() { base_t::dtor_unchecked(); } + + template > + choice_t& operator=(U&& u) noexcept + { + if (not base_t::template is()) { + base_t::dtor_unchecked(); + } + base_t::construct_unchecked(std::forward(u)); + return *this; + } + + template + void emplace(Args2&&... args) noexcept + { + base_t::dtor_unchecked(); + base_t::template construct_emplace_unchecked(std::forward(args)...); + } + + choice_t& operator=(const choice_t& other) noexcept + { + if (this != &other) { + base_t::dtor_unchecked(); + base_t::copy_unchecked(other); + } + return *this; + } + + choice_t& operator=(choice_t&& other) noexcept + { + base_t::dtor_unchecked(); + base_t::move_unchecked(std::move(other)); + return *this; + } + + bool holds_same_type(const choice_t& other) noexcept { return base_t::type_id == other.type_id; } +}; + +} // namespace srsran + +#endif // SRSRAN_CHOICE_TYPE_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/circular_array.h b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_array.h new file mode 100644 index 0000000..6874f48 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_array.h @@ -0,0 +1,65 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_CIRCULAR_ARRAY_H +#define SRSRAN_CIRCULAR_ARRAY_H + +#include +#include + +/** + * + * @file circular_array.h + * + * @brief Helper class to safely access elements of a std::array + * + * Protects from out-of-bounds access by applying modulo of it's length + * when using the [] operator for element access. + * + * This is useful for circular data structures, like TTIs or SNs. + */ + +namespace srsran { + +template +class circular_array +{ + std::array data{}; + +public: + using iterator = T*; + using const_iterator = const T*; + + T& operator[](std::size_t pos) { return data[pos % N]; } + const T& operator[](std::size_t pos) const { return data[pos % N]; } + + T* begin() { return data.begin(); } + const T* begin() const { return data.begin(); } + + T* end() { return data.end(); } + const T* end() const { return data.end(); } + + size_t size() const { return N; } +}; + +} // namespace srsran + +#endif // SRSRAN_CIRCULAR_ARRAY_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/circular_buffer.h b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_buffer.h new file mode 100644 index 0000000..67682b6 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_buffer.h @@ -0,0 +1,609 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_CIRCULAR_BUFFER_H +#define SRSRAN_CIRCULAR_BUFFER_H + +#include "srsran/adt/detail/type_storage.h" +#include "srsran/adt/expected.h" +#include "srsran/adt/pool/pool_utils.h" +#include "srsran/support/srsran_assert.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace srsran { + +namespace detail { + +template +size_t get_max_size(const std::array& a) +{ + return a.max_size(); +} + +template +size_t get_max_size(const std::vector& a) +{ + return a.capacity(); +} + +/** + * Base common class for definition of circular buffer data structures with the following features: + * - no allocations while pushing/popping new elements. Just an internal index update + * - it provides helper methods to add/remove objects + * - it provides an iterator interface to iterate over added elements in the buffer + * - not thread-safe + * @tparam Container underlying container type used as buffer (e.g. std::array or std::vector) + */ +template +class base_circular_buffer +{ + using storage_t = typename Container::value_type; + using T = typename storage_t::value_type; + + template + class iterator_impl + { + using parent_type = typename std::conditional::value, + base_circular_buffer, + const base_circular_buffer >::type; + + public: + using value_type = DataType; + using reference = DataType&; + using pointer = DataType*; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + iterator_impl(parent_type& parent_, size_t i) : parent(&parent_), idx(i) {} + + iterator_impl& operator++() + { + idx = (idx + 1) % parent->max_size(); + return *this; + } + iterator_impl operator++(int) + { + iterator_impl tmp(*this); + ++(*this); + return tmp; + } + iterator_impl operator+(difference_type n) + { + iterator_impl tmp(*this); + tmp += n; + return tmp; + } + iterator_impl& operator+=(difference_type n) + { + idx = (idx + n) % parent->max_size(); + return *this; + } + value_type* operator->() { return &get(); } + const value_type* operator->() const { return &get(); } + value_type& operator*() { return get(); } + const value_type& operator*() const { return get(); } + + bool operator==(const iterator_impl& it) const { return it.parent == parent and it.idx == idx; } + bool operator!=(const iterator_impl& it) const { return not(*this == it); } + + private: + void assert_idx_within_bounds() + { + srsran_assert(idx + (idx >= parent->rpos ? 0 : parent->max_size()) < parent->rpos + parent->count, + "index=%zd is out-of-bounds [%zd, %zd)", + idx, + parent->rpos, + parent->count); + } + value_type& get() + { + assert_idx_within_bounds(); + return parent->buffer[idx].get(); + } + const value_type& get() const + { + assert_idx_within_bounds(); + return parent->buffer[idx].get(); + } + parent_type* parent; + size_t idx; + }; + +public: + using value_type = T; + using difference_type = typename Container::difference_type; + using size_type = std::size_t; + + using iterator = iterator_impl; + using const_iterator = iterator_impl; + + base_circular_buffer() = default; + ~base_circular_buffer() { clear(); } + + template + typename std::enable_if::value>::type push(U&& t) + { + srsran_assert(not full(), "Circular buffer is full."); + size_t wpos = (rpos + count) % max_size(); + buffer[wpos].emplace(std::forward(t)); + count++; + } + + bool try_push(T&& t) + { + if (full()) { + return false; + } + push(std::move(t)); + return true; + } + + bool try_push(const T& t) + { + if (full()) { + return false; + } + push(t); + return true; + } + void pop() + { + srsran_assert(not empty(), "Cannot call pop() in empty circular buffer"); + buffer[rpos].destroy(); + rpos = (rpos + 1) % max_size(); + count--; + } + T& top() + { + srsran_assert(not empty(), "Cannot call top() in empty circular buffer"); + return buffer[rpos].get(); + } + const T& top() const + { + srsran_assert(not empty(), "Cannot call top() in empty circular buffer"); + return buffer[rpos].get(); + } + void clear() + { + for (size_t i = 0; i < count; ++i) { + buffer[(rpos + i) % max_size()].destroy(); + } + count = 0; + } + + bool full() const { return count == max_size(); } + bool empty() const { return count == 0; } + size_t size() const { return count; } + size_t max_size() const { return detail::get_max_size(buffer); } + + T& operator[](size_t i) + { + srsran_assert(i < count, "Out-of-bounds access to circular buffer (%zd >= %zd)", i, count); + return buffer[(rpos + i) % max_size()].get(); + } + const T& operator[](size_t i) const + { + srsran_assert(i < count, "Out-of-bounds access to circular buffer (%zd >= %zd)", i, count); + return buffer[(rpos + i) % max_size()].get(); + } + + iterator begin() { return iterator(*this, rpos); } + const_iterator begin() const { return const_iterator(*this, rpos); } + iterator end() { return iterator(*this, (rpos + count) % max_size()); } + const_iterator end() const { return const_iterator(*this, (rpos + count) % max_size()); } + + template + bool apply_first(const F& func) + { + for (auto it = begin(); it != end(); it++) { + if (func(*it)) { + return true; + } + } + return false; + } + +protected: + base_circular_buffer(size_t rpos_, size_t count_) : rpos(rpos_), count(count_) {} + template + base_circular_buffer(size_t rpos_, size_t count_, BufferArgs&&... args) : + rpos(rpos_), count(count_), buffer(std::forward(args)...) + {} + + Container buffer; + size_t rpos = 0; + size_t count = 0; +}; + +/** + * Base common class for definition of blocking queue data structures with the following features: + * - it stores pushed/popped samples in an internal circular buffer + * - provides blocking and non-blocking push/pop APIs + * - thread-safe + * @tparam CircBuffer underlying circular buffer data type (e.g. static_circular_buffer or dyn_circular_buffer) + * @tparam PushingFunc function void(const T&) called while pushing an element to the queue + * @tparam PoppingFunc function void(const T&) called while popping an element from the queue + */ +template +class base_blocking_queue +{ + using T = typename CircBuffer::value_type; + +public: + template + base_blocking_queue(PushingFunc push_func_, PoppingFunc pop_func_, Args&&... args) : + circ_buffer(std::forward(args)...), push_func(push_func_), pop_func(pop_func_) + {} + base_blocking_queue(const base_blocking_queue&) = delete; + base_blocking_queue(base_blocking_queue&&) = delete; + base_blocking_queue& operator=(const base_blocking_queue&) = delete; + base_blocking_queue& operator=(base_blocking_queue&&) = delete; + + void stop() + { + std::unique_lock lock(mutex); + if (active) { + active = false; + if (nof_waiting > 0) { + // Stop pending pushing/popping threads + do { + lock.unlock(); + cvar_empty.notify_all(); + cvar_full.notify_all(); + std::this_thread::yield(); + lock.lock(); + } while (nof_waiting > 0); + } + + // Empty queue + circ_buffer.clear(); + } + } + + bool try_push(const T& t) { return push_(t, false); } + srsran::error_type try_push(T&& t) { return push_(std::move(t), false); } + bool push_blocking(const T& t) { return push_(t, true); } + srsran::error_type push_blocking(T&& t) { return push_(std::move(t), true); } + bool try_pop(T& obj) { return pop_(obj, false); } + T pop_blocking(bool* success = nullptr) + { + T obj{}; + bool ret = pop_(obj, true); + if (success != nullptr) { + *success = ret; + } + return obj; + } + bool pop_wait_until(T& obj, const std::chrono::system_clock::time_point& until) { return pop_(obj, true, &until); } + void clear() + { + T obj; + while (pop_(obj, false)) { + } + } + + size_t size() const + { + std::lock_guard lock(mutex); + return circ_buffer.size(); + } + bool empty() const + { + std::lock_guard lock(mutex); + return circ_buffer.empty(); + } + bool full() const + { + std::lock_guard lock(mutex); + return circ_buffer.full(); + } + size_t max_size() const + { + std::lock_guard lock(mutex); + return circ_buffer.max_size(); + } + bool is_stopped() const + { + std::lock_guard lock(mutex); + return not active; + } + template + bool try_call_on_front(F&& f) + { + std::lock_guard lock(mutex); + if (not circ_buffer.empty()) { + f(circ_buffer.top()); + return true; + } + return false; + } + + template + bool apply_first(const F& func) + { + std::lock_guard lock(mutex); + return circ_buffer.apply_first(func); + } + + PushingFunc push_func; + PoppingFunc pop_func; + +protected: + bool active = true; + uint8_t nof_waiting = 0; + mutable std::mutex mutex; + std::condition_variable cvar_empty, cvar_full; + CircBuffer circ_buffer; + + ~base_blocking_queue() { stop(); } + + bool push_(const T& t, bool block_mode) + { + std::unique_lock lock(mutex); + if (not active) { + return false; + } + if (circ_buffer.full()) { + if (not block_mode) { + return false; + } + nof_waiting++; + while (circ_buffer.full() and active) { + cvar_full.wait(lock); + } + nof_waiting--; + if (not active) { + return false; + } + } + push_func(t); + circ_buffer.push(t); + lock.unlock(); + cvar_empty.notify_one(); + return true; + } + srsran::error_type push_(T&& t, bool block_mode) + { + std::unique_lock lock(mutex); + if (not active) { + return std::move(t); + } + if (circ_buffer.full()) { + if (not block_mode) { + return std::move(t); + } + nof_waiting++; + while (circ_buffer.full() and active) { + cvar_full.wait(lock); + } + nof_waiting--; + if (not active) { + return std::move(t); + } + } + push_func(t); + circ_buffer.push(std::move(t)); + lock.unlock(); + cvar_empty.notify_one(); + return {}; + } + + bool pop_(T& obj, bool block, const std::chrono::system_clock::time_point* until = nullptr) + { + std::unique_lock lock(mutex); + if (not active) { + return false; + } + if (circ_buffer.empty()) { + if (not block) { + return false; + } + nof_waiting++; + if (until == nullptr) { + cvar_empty.wait(lock, [this]() { return not circ_buffer.empty() or not active; }); + } else { + cvar_empty.wait_until(lock, *until, [this]() { return not circ_buffer.empty() or not active; }); + } + nof_waiting--; + if (circ_buffer.empty()) { + // either queue got deactivated or there was a timeout + return false; + } + } + obj = std::move(circ_buffer.top()); + pop_func(obj); + circ_buffer.pop(); + lock.unlock(); + cvar_full.notify_one(); + return true; + } +}; + +} // namespace detail + +/** + * Circular buffer with fixed, embedded buffer storage via a std::array. + * - Single allocation at object creation for std::array. Given that the buffer size is known at compile-time, the + * circular iteration over the buffer may be more optimized (e.g. when N is a power of 2, % operator can be avoided) + * - not thread-safe + * @tparam T value type stored by buffer + * @tparam N size of the queue + */ +template +class static_circular_buffer : public detail::base_circular_buffer, N> > +{ + using base_t = detail::base_circular_buffer, N> >; + +public: + static_circular_buffer() = default; + static_circular_buffer(const static_circular_buffer& other) : base_t(other.rpos, other.count) + { + static_assert(std::is_copy_constructible::value, "T must be copy-constructible"); + std::uninitialized_copy(other.begin(), other.end(), base_t::begin()); + } + static_circular_buffer(static_circular_buffer&& other) noexcept : base_t(other.rpos, other.count) + { + static_assert(std::is_move_constructible::value, "T must be move-constructible"); + for (size_t i = 0; i < other.count; ++i) { + size_t idx = (other.rpos + i) % other.max_size(); + base_t::buffer[idx].move_ctor(std::move(other.buffer[idx])); + } + other.clear(); + } + static_circular_buffer& operator=(const static_circular_buffer& other) + { + if (this == &other) { + return *this; + } + base_t::clear(); + base_t::rpos = other.rpos; + base_t::count = other.count; + for (size_t i = 0; i < other.count; ++i) { + size_t idx = (other.rpos + i) % other.max_size(); + base_t::buffer[idx].copy_ctor(other.buffer[idx]); + } + return *this; + } + static_circular_buffer& operator=(static_circular_buffer&& other) noexcept + { + base_t::clear(); + base_t::rpos = other.rpos; + base_t::count = other.count; + for (size_t i = 0; i < other.count; ++i) { + size_t idx = (other.rpos + i) % other.max_size(); + base_t::buffer[idx].move_ctor(std::move(other.buffer[idx])); + } + other.clear(); + return *this; + } +}; + +/** + * Circular buffer with buffer storage via a std::vector. + * - size can be defined at run-time. + * - not thread-safe + * @tparam T value type stored by buffer + */ +template +class dyn_circular_buffer : public detail::base_circular_buffer > > +{ + using base_t = detail::base_circular_buffer > >; + +public: + dyn_circular_buffer() = default; + explicit dyn_circular_buffer(size_t max_size) : base_t(0, 0, max_size) {} + dyn_circular_buffer(dyn_circular_buffer&& other) noexcept : base_t(other.rpos, other.count, std::move(other.buffer)) + { + other.count = 0; + other.rpos = 0; + } + dyn_circular_buffer(const dyn_circular_buffer& other) : base_t(other.rpos, other.count, other.max_size()) + { + static_assert(std::is_copy_constructible::value, "T must be copy-constructible"); + for (size_t i = 0; i < other.count; ++i) { + size_t idx = (other.rpos + i) % other.max_size(); + base_t::buffer[idx].copy_ctor(other.buffer[idx]); + } + } + dyn_circular_buffer& operator=(dyn_circular_buffer other) noexcept + { + swap(other); + other.clear(); + return *this; + } + + void swap(dyn_circular_buffer& other) noexcept + { + std::swap(base_t::rpos, other.rpos); + std::swap(base_t::count, other.count); + std::swap(base_t::buffer, other.buffer); + } + + void set_size(size_t sz) + { + srsran_assert(base_t::empty() or sz == base_t::size(), + "Dynamic resizes not supported when circular buffer is not empty"); + base_t::buffer.resize(sz); + } +}; + +/** + * Blocking queue with fixed, embedded buffer storage via a std::array. + * - Blocking push/pop API via push_blocking(...) and pop_blocking(...) methods + * - Non-blocking push/pop API via try_push(...) and try_pop(...) methods + * - Only one initial allocation for the std::array + * - thread-safe + * @tparam T value type stored by buffer + * @tparam N size of queue + * @tparam PushingCallback function void(const T&) called while pushing an element to the queue + * @tparam PoppingCallback function void(const T&) called while popping an element from the queue + */ +template +class static_blocking_queue + : public detail::base_blocking_queue, PushingCallback, PoppingCallback> +{ + using base_t = detail::base_blocking_queue, PushingCallback, PoppingCallback>; + +public: + explicit static_blocking_queue(PushingCallback push_callback = {}, PoppingCallback pop_callback = {}) : + base_t(push_callback, pop_callback) + {} +}; + +/** + * Blocking queue with buffer storage represented via a std::vector. Features: + * - Blocking push/pop API via push_blocking(...) and pop_blocking(...) methods + * - Non-blocking push/pop API via try_push(...) and try_pop(...) methods + * - Size can be defined at runtime. + * - thread-safe + * @tparam T value type stored by buffer + * @tparam PushingCallback function void(const T&) called while pushing an element to the queue + * @tparam PoppingCallback function void(const T&) called while popping an element from the queue + */ +template +class dyn_blocking_queue : public detail::base_blocking_queue, PushingCallback, PoppingCallback> +{ + using base_t = detail::base_blocking_queue, PushingCallback, PoppingCallback>; + +public: + dyn_blocking_queue() = default; + explicit dyn_blocking_queue(size_t size, PushingCallback push_callback = {}, PoppingCallback pop_callback = {}) : + base_t(push_callback, pop_callback, size) + {} + void set_size(size_t size) { base_t::circ_buffer.set_size(size); } +}; + +} // namespace srsran + +#endif // SRSRAN_CIRCULAR_BUFFER_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/circular_map.h b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_map.h new file mode 100644 index 0000000..eee22a6 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/circular_map.h @@ -0,0 +1,336 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_ID_MAP_H +#define SRSRAN_ID_MAP_H + +#include "detail/type_storage.h" +#include "expected.h" +#include "srsran/support/srsran_assert.h" +#include + +namespace srsran { + +template +class static_circular_map +{ + static_assert(std::is_integral::value and std::is_unsigned::value, "Map key must be an unsigned integer"); + + using obj_t = std::pair; + +public: + using key_type = K; + using mapped_type = T; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + + class iterator + { + public: + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + iterator() = default; + iterator(static_circular_map* map, size_t idx_) : ptr(map), idx(idx_) + { + if (idx < ptr->capacity() and not ptr->present[idx]) { + ++(*this); + } + } + + iterator& operator++() + { + while (++idx < ptr->capacity() and not ptr->present[idx]) { + } + return *this; + } + + obj_t& operator*() + { + srsran_assert(idx < ptr->capacity(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->capacity()); + return ptr->get_obj_(idx); + } + obj_t* operator->() + { + srsran_assert(idx < ptr->capacity(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->capacity()); + return &ptr->get_obj_(idx); + } + const obj_t* operator*() const + { + srsran_assert(idx < ptr->capacity(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->capacity()); + return &ptr->get_obj_(idx); + } + const obj_t* operator->() const + { + srsran_assert(idx < ptr->capacity(), "Iterator out-of-bounds (%zd >= %zd)", idx, ptr->capacity()); + return &ptr->get_obj_(idx); + } + + bool operator==(const iterator& other) const { return ptr == other.ptr and idx == other.idx; } + bool operator!=(const iterator& other) const { return not(*this == other); } + + private: + friend class static_circular_map; + static_circular_map* ptr = nullptr; + size_t idx = 0; + }; + class const_iterator + { + public: + const_iterator() = default; + const_iterator(const static_circular_map* map, size_t idx_) : ptr(map), idx(idx_) + { + if (idx < ptr->capacity() and not ptr->present[idx]) { + ++(*this); + } + } + + const_iterator& operator++() + { + while (++idx < ptr->capacity() and not ptr->present[idx]) { + } + return *this; + } + + const obj_t* operator*() const { return &ptr->buffer[idx].get(); } + const obj_t* operator->() const { return &ptr->buffer[idx].get(); } + + bool operator==(const const_iterator& other) const { return ptr == other.ptr and idx == other.idx; } + bool operator!=(const const_iterator& other) const { return not(*this == other); } + + private: + friend class static_circular_map; + const static_circular_map* ptr = nullptr; + size_t idx = 0; + }; + + static_circular_map() { std::fill(present.begin(), present.end(), false); } + static_circular_map(const static_circular_map& other) : present(other.present), count(other.count) + { + for (size_t idx = 0; idx < other.capacity(); ++idx) { + if (present[idx]) { + buffer[idx].template emplace(other.get_obj_(idx)); + } + } + } + static_circular_map(static_circular_map&& other) noexcept : present(other.present), count(other.count) + { + for (size_t idx = 0; idx < other.capacity(); ++idx) { + if (present[idx]) { + buffer[idx].template emplace(std::move(other.get_obj_(idx))); + } + } + other.clear(); + } + ~static_circular_map() { clear(); } + static_circular_map& operator=(const static_circular_map& other) + { + if (this == &other) { + return *this; + } + for (size_t idx = 0; idx < other.capacity(); ++idx) { + copy_if_present_helper(buffer[idx], other.buffer[idx], present[idx], other.present[idx]); + } + count = other.count; + present = other.present; + } + static_circular_map& operator=(static_circular_map&& other) noexcept + { + for (size_t idx = 0; idx < other.capacity(); ++idx) { + move_if_present_helper(buffer[idx], other.buffer[idx], present[idx], other.present[idx]); + } + count = other.count; + present = other.present; + other.clear(); + return *this; + } + + bool contains(K id) const + { + size_t idx = id % N; + return present[idx] and get_obj_(idx).first == id; + } + + bool insert(K id, const T& obj) + { + size_t idx = id % N; + if (present[idx]) { + return false; + } + buffer[idx].template emplace(id, obj); + present[idx] = true; + count++; + return true; + } + srsran::expected insert(K id, T&& obj) + { + size_t idx = id % N; + if (present[idx]) { + return srsran::expected(std::move(obj)); + } + buffer[idx].template emplace(id, std::move(obj)); + present[idx] = true; + count++; + return iterator(this, idx); + } + + template + void overwrite(K id, U&& obj) + { + size_t idx = id % N; + if (present[idx]) { + erase(buffer[idx].get().first); + } + insert(id, std::forward(obj)); + } + + bool erase(K id) + { + if (not contains(id)) { + return false; + } + size_t idx = id % N; + get_obj_(idx).~obj_t(); + present[idx] = false; + --count; + return true; + } + + iterator erase(iterator it) + { + srsran_assert(it.idx < N and it.ptr == this, "Iterator out-of-bounds (%zd >= %zd)", it.idx, N); + iterator next = it; + ++next; + present[it.idx] = false; + get_obj_(it.idx).~obj_t(); + --count; + return next; + } + + void clear() + { + for (size_t i = 0; i < N; ++i) { + if (present[i]) { + present[i] = false; + get_obj_(i).~obj_t(); + } + } + count = 0; + } + + T& operator[](K id) + { + srsran_assert(contains(id), "Accessing non-existent ID=%zd", (size_t)id); + return get_obj_(id % N).second; + } + const T& operator[](K id) const + { + srsran_assert(contains(id), "Accessing non-existent ID=%zd", (size_t)id); + return get_obj_(id % N).second; + } + + size_t size() const { return count; } + bool empty() const { return count == 0; } + bool full() const { return count == N; } + bool has_space(K id) { return not present[id % N]; } + size_t capacity() const { return N; } + + iterator begin() { return iterator(this, 0); } + iterator end() { return iterator(this, N); } + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, N); } + + iterator find(K id) + { + if (contains(id)) { + return iterator(this, id % N); + } + return end(); + } + const_iterator find(K id) const + { + if (contains(id)) { + return const_iterator(this, id % N); + } + return end(); + } + +private: + obj_t& get_obj_(size_t idx) { return buffer[idx].get(); } + const obj_t& get_obj_(size_t idx) const { return buffer[idx].get(); } + + std::array, N> buffer; + std::array present; + size_t count = 0; +}; + +/** + * Operates like a circular map, but automatically assigns the ID/key to inserted objects in a monotonically + * increasing way. The assigned IDs are not necessarily contiguous, as they are selected based on the available slots + * in the circular map + * @tparam K type of ID/key + * @tparam T object being inserted + * @tparam MAX_N maximum size of pool + */ +template +class static_id_obj_pool : private static_circular_map +{ + using base_t = static_circular_map; + +public: + using iterator = typename base_t::iterator; + using const_iterator = typename base_t::const_iterator; + + using base_t::operator[]; + using base_t::begin; + using base_t::contains; + using base_t::empty; + using base_t::end; + using base_t::erase; + using base_t::find; + using base_t::full; + using base_t::size; + + explicit static_id_obj_pool(K first_id = 0) : next_id(first_id) {} + + template + srsran::expected insert(U&& t) + { + if (full()) { + return srsran::default_error_t{}; + } + while (not base_t::has_space(next_id)) { + ++next_id; + } + base_t::insert(next_id, std::forward(t)); + return next_id++; + } + +private: + K next_id = 0; +}; + +} // namespace srsran + +#endif // SRSRAN_ID_MAP_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/detail/index_sequence.h b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/index_sequence.h new file mode 100644 index 0000000..9825ab8 --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/index_sequence.h @@ -0,0 +1,45 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef CPP_TESTS_INDEX_SEQUENCE_H +#define CPP_TESTS_INDEX_SEQUENCE_H + +#include + +namespace srsran { + +template +struct index_sequence {}; + +template +struct index_sequence_helper : public index_sequence_helper {}; + +template +struct index_sequence_helper<0U, Next...> { + using type = index_sequence; +}; + +template +using make_index_sequence = typename index_sequence_helper::type; + +} // namespace srsran + +#endif // CPP_TESTS_INDEX_SEQUENCE_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_storage.h b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_storage.h new file mode 100644 index 0000000..9f98bef --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_storage.h @@ -0,0 +1,112 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_TYPE_STORAGE_H +#define SRSRAN_TYPE_STORAGE_H + +#include +#include +#include +#include + +namespace srsran { + +namespace detail { + +// NOTE: gcc 4.8.5 is missing std::max_align_t. Need to create a struct +union max_alignment_t { + char c; + float f; + uint32_t i; + uint64_t i2; + double d; + long double d2; + uint32_t* ptr; +}; +const static size_t max_alignment = alignof(max_alignment_t); + +template +struct type_storage { + using value_type = T; + + template + void emplace(Args&&... args) + { + new (&buffer) T(std::forward(args)...); + } + void destroy() { get().~T(); } + void copy_ctor(const type_storage& other) { emplace(other.get()); } + void move_ctor(type_storage&& other) { emplace(std::move(other.get())); } + void copy_assign(const type_storage& other) { get() = other.get(); } + void move_assign(type_storage&& other) { get() = std::move(other.get()); } + + T& get() { return reinterpret_cast(buffer); } + const T& get() const { return reinterpret_cast(buffer); } + + void* addr() { return static_cast(&buffer); } + const void* addr() const { return static_cast(&buffer); } + explicit operator void*() { return addr(); } + + const static size_t obj_size = sizeof(T) > MinSize ? sizeof(T) : MinSize; + const static size_t align_size = alignof(T) > AlignSize ? alignof(T) : AlignSize; + + typename std::aligned_storage::type buffer; +}; + +template +void copy_if_present_helper(type_storage& lhs, + const type_storage& rhs, + bool lhs_present, + bool rhs_present) +{ + if (lhs_present and rhs_present) { + lhs.get() = rhs.get(); + } + if (lhs_present) { + lhs.destroy(); + } + if (rhs_present) { + lhs.copy_ctor(rhs); + } +} + +template +void move_if_present_helper(type_storage& lhs, + type_storage& rhs, + bool lhs_present, + bool rhs_present) +{ + if (lhs_present and rhs_present) { + lhs.move_assign(std::move(rhs)); + } + if (lhs_present) { + lhs.destroy(); + } + if (rhs_present) { + lhs.move_ctor(std::move(rhs)); + } +} + +} // namespace detail + +} // namespace srsran + +#endif // SRSRAN_TYPE_STORAGE_H diff --git a/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_utils.h b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_utils.h new file mode 100644 index 0000000..961bc1e --- /dev/null +++ b/srsRAN_4G_mirror/lib/include/srsran/adt/detail/type_utils.h @@ -0,0 +1,342 @@ +/** + * Copyright 2013-2021 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN 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 Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSRAN_TYPE_UTILS_H +#define SRSRAN_TYPE_UTILS_H + +#include "srsran/adt/expected.h" +#include +#include +#include +#include +#include + +namespace srsran { + +/************************************ + * get_type_name methods + ***********************************/ + +//! Helper to print the name of a type for logging +/** + * @brief Helper function that returns a type name string + */ +#if defined(__GNUC__) && !defined(__clang__) + +template +std::string get_type_name() +{ + static const std::string s = [](const char* funcname) { + static const char* pos1 = strchr(funcname, '=') + 2; + static const char* pos2 = strchr(pos1, ';'); + std::string s2{pos1, pos2}; + size_t colon_pos = s2.rfind(':'); + std::string s3 = colon_pos == std::string::npos ? s2 : s2.substr(colon_pos + 1, s2.size()); + return s3.find('>') == std::string::npos ? s3 : s2; + }(__PRETTY_FUNCTION__); + return s; +} + +#elif defined(__clang__) +template +std::string get_type_name() +{ + static const char* funcname = __PRETTY_FUNCTION__; + static const std::string s = []() { + static const char* pos1 = strchr(funcname, '=') + 2; + static const char* pos2 = strchr(pos1, ']'); + std::string s2{pos1, pos2}; + size_t colon_pos = s2.rfind(':'); + std::string s3 = colon_pos == std::string::npos ? s2 : s2.substr(colon_pos + 1, s2.size()); + return s3.find('>') == std::string::npos ? s3 : s2; + }(); + return s; +} + +#else +template +std::string get_type_name() +{ + return "anonymous"; +} +#endif + +//! This version leverages argument type deduction for shorter syntax. (e.g. get_type_name(var)) +template +std::string get_type_name(const T& t) +{ + return get_type_name(); +} + +/************************************ + * type_list + ***********************************/ + +constexpr size_t invalid_type_index = std::numeric_limits::max(); + +template +struct type_list {}; + +template +constexpr size_t type_list_size(type_list t) +{ + return sizeof...(Args); +} + +/************************************ + * get_index_type/get_type_index + ***********************************/ + +namespace type_utils { + +//! Get Index of a type in a list of types (in reversed order) +template +struct type_list_reverse_index; + +template +struct type_list_reverse_index { + static constexpr size_t index = + std::is_same::value ? sizeof...(Types) : type_list_reverse_index::index; +}; + +template +struct type_list_reverse_index { + static constexpr size_t index = invalid_type_index; +}; + +//! Get a type of an index in a list of types +template +struct get_type_reverse; + +template +struct get_type_reverse { + using type = + typename std::conditional::type>::type; +}; + +template +struct get_type_reverse { + using type = void; +}; + +} // namespace type_utils + +//! Get index of T in Types... +template +constexpr size_t get_type_index() +{ + using namespace type_utils; + return (type_list_reverse_index::index == invalid_type_index) + ? invalid_type_index + : sizeof...(Types) - type_list_reverse_index::index - 1; +} + +//! If T is in Types... +template +constexpr bool type_list_contains() +{ + return get_type_index() != invalid_type_index; +} + +//! Get type of index I in Types... +template +struct get_index_type { + using type = typename type_utils::get_type_reverse::type; +}; + +/************************** + * Filter utils + *************************/ + +namespace type_utils { + +//! pushes type to front of type_list +template +struct push_front; +template +struct push_front > { + using type = type_list; +}; +template <> +struct push_front<> { + using type = type_list<>; +}; + +//! Creates a type_list with the "Types..." for which Predicate::value is true +template