diff --git a/ci-scripts/Jenkinsfile-poll-gNB-UE b/ci-scripts/Jenkinsfile-poll-gNB-UE new file mode 100644 index 0000000000000000000000000000000000000000..dfac9b969de149dc38de0912444876cd236b1334 --- /dev/null +++ b/ci-scripts/Jenkinsfile-poll-gNB-UE @@ -0,0 +1,380 @@ +#!/bin/groovy +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org +*/ + + +// Abstraction function to send social media messages: +// like on Slack or Mattermost +def sendSocialMediaMessage(pipeChannel, pipeColor, pipeMessage) { + if (params.pipelineUsesSlack != null) { + if (params.pipelineUsesSlack) { + slackSend channel: pipeChannel, color: pipeColor, message: pipeMessage + } + } +} + +// Location of the test XML file to be run +def testXMLFile = params.pythonTestXmlFile +def mainPythonAllXmlFiles = "" +def buildStageStatus = true + +// Name of the phone resource +def ciUSRPsResource = params.USRPsResource + +// Terminate Status +def termUE = 0 +def termENB = 1 +def termStatusArray = new Boolean[2] +termStatusArray[termUE] = false +termStatusArray[termENB] = false + +// Global Parameters. +def eNB_Repository +def eNB_Branch +def eNB_CommitID +def eNB_AllowMergeRequestProcess = false +def eNB_TargetBranch +def PROJECT_NAME = "test-boris" +def GIT_COMMIT_AUTHORi +def GIT_COMMIT_EMAIL +def testStageName +// Reversing list because pop() will take the last (right-most) element +//def modeList = ['TesteNB', 'TestUE', 'TesteNB'].reverse() + +// Global Parameters not to break the main.py command line and code. +def ADB_IPAddress = "none" +def ADB_Username = "none" +def ADB_Password = "none" +def EPC_IPAddress = "none" +def EPC_Username = "none" +def EPC_Password = "none" + + + +pipeline { + agent { + label pythonExecutor + } + options { + disableConcurrentBuilds() + gitLabConnection('OAI GitLab') + ansiColor('xterm') + lock (ciUSRPsResource) + } + + stages { + stage ('Retrieve latest from branch') { + steps { + script { + checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: 'https://gitlab.eurecom.fr/oai/openairinterface5g.git']]]) + sh "git clean -x -d -ff" + sh "git log -n1" + } + } + } + stage ("print latest commit info") { + steps { + script { + echo "Building on: " + echo " Repository -- ${GIT_URL}" + echo " Branch -- ${GIT_BRANCH}" + echo " Commit -- ${GIT_COMMIT}" + } + } + } + stage ("Verify Parameters") { + steps { + script { + JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"' + JOB_TIMESTAMP = JOB_TIMESTAMP.trim() + + echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' + def allParametersPresent = true + + // It is already too late to check it + if (params.pythonExecutor != null) { + echo "eNB CI executor node : ${pythonExecutor}" + } + if (params.eNB_Repository == null) { + eNB_Repository = GIT_URL + } else { + eNB_Repository = params.eNB_Repository + } + echo "eNB_Repository = ${eNB_Repository}" + if (params.eNB_Branch== null) { + eNB_Branch = GIT_BRANCH + } else { + eNB_Branch = params.eNB_Branch + } + echo "eNB_Branch = ${eNB_Branch}" + if (params.eNB_CommitID == null) { + eNB_CommitID = GIT_COMMIT + } else { + eNB_CommitID = params.eNB_CommitID + } + echo "eNB_CommitID = ${eNB_CommitID}" + // If not present picking a default Stage Name + if (params.pipelineTestStageName == null) { + // picking default + testStageName = 'Template Test Stage' + } else { + testStageName = params.pipelineTestStageName + } + + if (params.USRPsResource == null) { + allParametersPresent = false + } + + if (params.eNB_IPAddress == null) { + allParametersPresent = false + } + if (params.UE_IPAddress == null) { + allParametersPresent = false + } + if (params.eNB_SourceCodePath == null) { + allParametersPresent = false + } + if (params.eNB_Credentials == null) { + allParametersPresent = false + } + if (params.UE_Credentials == null) { + allParametersPresent = false + } + GIT_COMMIT_AUTHOR = sh ( + script: 'git show -s --pretty=%an', + returnStdout: true + ).trim() + echo "The author of the commit is: ${GIT_COMMIT_AUTHOR}" + GIT_COMMIT_EMAIL = sh ( + script: 'git show -s --pretty=%ae', + returnStdout: true + ).trim() + echo "The email of the author is: ${GIT_COMMIT_EMAIL}" + if (allParametersPresent) { + echo "All parameters are present" + } else { + echo "Some parameters are missing" + sh "./ci-scripts/fail.sh" + } + } + } + } + + stage ("Build and Test") { + steps { + script { + dir ('ci-scripts') { + // If not present picking a default XML file + if (params.pythonTestXmlFile == null) { + // picking default + testXMLFile = 'xml_files/gnb_usrp_build.xml' + echo "Test XML file(default): ${testXMLFile}" + mainPythonAllXmlFiles += "--XMLTestFile=" + testXMLFile + " " + } else { + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { + if (fileExists(xmlFile)) { + mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " " + echo "Test XML file : ${xmlFile}" + } + } + } + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.UE_Credentials}", usernameVariable: 'UE_Username', passwordVariable: 'UE_Password'] + ]) { + sh "python3 main.py --mode=InitiateHtml --eNBRepository=${eNB_Repository} --eNBBranch=${eNB_Branch} --eNBCommitID=${eNB_CommitID} --eNB_AllowMerge=${eNB_AllowMergeRequestProcess} --ADBIPAddress=${ADB_IPAddress} --ADBUserName=${ADB_Username} --ADBPassword=${ADB_Password} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} ${mainPythonAllXmlFiles}" + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { + if (fileExists(xmlFile)) { + try { + sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --UEIPAddress=${params.eNB_IPAddress} --UEUserName=${eNB_Username} --UEPassword=${eNB_Password} --eNBBranch=${eNB_Branch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --UESourceCodePath=${params.eNB_SourceCodePath} --eNBRepository=${eNB_Repository} --eNBCommitID=${eNB_CommitID} --ADBIPAddress=${ADB_IPAddress} --EPCIPAddress=${EPC_IPAddress} --XMLTestFile=${xmlFile}" + } catch (Exception e) { + currentBuild.result = 'FAILURE' + buildStageStatus = false + } + } + } + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + } + } + } + } + } + + stage ("Terminate") { + parallel { + stage('Terminate NR UE') { + steps { + echo '\u2705 \u001B[32mTerminate NR UE\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'UE_Username', passwordVariable: 'UE_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateOAIUE --UEIPAddress=${params.eNB_IPAddress} --UEUserName=${UE_Username} --UEPassword=${UE_Password}" + } + } + post { + success { + script { + termStatusArray[termUE] = true + } + } + } + } + stage('Terminate NR eNB') { + steps { + echo '\u2705 \u001B[32mTerminate NR eNB\u001B[0m' + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + } + } + post { + success { + script { + termStatusArray[termENB] = true + } + } + } + } + } + } + + stage('Log Collection') { + parallel { + stage('Log Collection (gNB and NR UE - Build)') { + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (gNB and NR UE - Build)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" + + echo '\u2705 \u001B[32mLog Transfer (gNB and NR UE - Build)\u001B[0m' + sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("build.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "build.log.${env.BUILD_ID}.zip" + } + } + } + } + stage('Log Collection (gNB - Run)') { + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (gNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" + + echo '\u2705 \u001B[32mLog Transfer (gNB - Run)\u001B[0m' + sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("enb.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "enb.log.${env.BUILD_ID}.zip" + } + if(fileExists("ci-scripts/test_results.html")) { + sh "mv ci-scripts/test_results.html test_results-${JOB_NAME}.html" + sh "sed -i -e 's#TEMPLATE_JOB_NAME#${JOB_NAME}#' -e 's@build #TEMPLATE_BUILD_ID@build #${BUILD_ID}@' -e 's#Build-ID: TEMPLATE_BUILD_ID#Build-ID: <a href=\"${BUILD_URL}\">${BUILD_ID}</a>#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" + archiveArtifacts "test_results-${JOB_NAME}.html" + } + } + } + } + stage('Log Collection (NR UE - Run)') { + steps { + withCredentials([ + [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] + ]) { + echo '\u2705 \u001B[32mLog Collection (gNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollectOAIUE --UEIPAddress=${params.eNB_IPAddress} --UEUserName=${eNB_Username} --UEPassword=${eNB_Password} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --UESourceCodePath=${params.eNB_SourceCodePath}" + + echo '\u2705 \u001B[32mLog Transfer (gNB - Run)\u001B[0m' + sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/ue.log.zip ./ue.log.${env.BUILD_ID}.zip || true" + } + script { + if(fileExists("ue.log.${env.BUILD_ID}.zip")) { + archiveArtifacts "ue.log.${env.BUILD_ID}.zip" + } + } + } + } + } + } + } + + post { + always { + script { + if ("MERGE".equals(env.gitlabActionType)) { + echo "This is a MERGE event" + } else { + gitlabCommitStatus(name: "Test-gNB-nrUE") { + if ((currentBuild.result == null) || (currentBuild.result == 'SUCCESS')) { + echo "Setting the gitlab commit status to pass" + } else { + sh "./ci-scripts/fail.sh" + } + } + } + emailext attachmentsPattern: '*results*.html', + body: '''Hi, +Here are attached HTML report files for $PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS! + +Regards, +OAI CI Team''', + replyTo: 'no-reply@openairinterface.org', + subject: '$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!', + to: GIT_COMMIT_EMAIL + } + } + success { + script { + def message = "OAI " + JOB_NAME + " build (" + BUILD_ID + "): passed (" + BUILD_URL + ")" + if ("MERGE".equals(env.gitlabActionType)) { + echo "This is a MERGE event" + //addGitLabMRComment comment: message + def message2 = "OAI " + JOB_NAME + " build (" + BUILD_ID + "): passed (" + BUILD_URL + ") -- MergeRequest #" + env.gitlabMergeRequestIid + " (" + env.gitlabMergeRequestTitle + ")" + sendSocialMediaMessage('ci-test', 'good', message2) + } else { + sendSocialMediaMessage('ci-test', 'good', message) + } + } + } + failure { + script { + def message = "OAI " + JOB_NAME + " build (" + BUILD_ID + "): failed (" + BUILD_URL + ")" + if ("MERGE".equals(env.gitlabActionType)) { + echo "This is a MERGE event" + //addGitLabMRComment comment: message + def message2 = "OAI " + JOB_NAME + " build (" + BUILD_ID + "): failed (" + BUILD_URL + ") -- MergeRequest #" + env.gitlabMergeRequestIid + " (" + env.gitlabMergeRequestTitle + ")" + sendSocialMediaMessage('ci-test', 'danger', message2) + } else { + sendSocialMediaMessage('ci-test', 'danger', message) + } + } + } + } +} + diff --git a/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf new file mode 100644 index 0000000000000000000000000000000000000000..e71bb00ffbe9879646bde948ad759653401b790e --- /dev/null +++ b/ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf @@ -0,0 +1,298 @@ +Active_gNBs = ( "gNB-Eurecom-5GNRBox"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + + cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-Eurecom-5GNRBox"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({mcc = 208; mnc = 93; mnc_length = 2;}); + + tr_s_preference = "local_mac" + + ////////// Physical parameters: + + component_carriers = ( + { + node_function = "3GPP_gNODEB"; + node_timing = "synch_to_ext_device"; + node_synch_ref = 0; + frame_type = "TDD"; + DL_prefix_type = "NORMAL"; + UL_prefix_type = "NORMAL"; + eutra_band = 78; + downlink_frequency = 3510000000L; + uplink_frequency_offset = -120000000; + Nid_cell = 0; + N_RB_DL = 106; + nb_antenna_ports = 1; + nb_antennas_tx = 1; + nb_antennas_rx = 1; + tx_gain = 90; + rx_gain = 125; + MIB_subCarrierSpacingCommon = 30; + MIB_ssb_SubcarrierOffset = 0; + MIB_dmrs_TypeA_Position = 2; + pdcch_ConfigSIB1 = 0; + SIB1_frequencyOffsetSSB = "khz5"; + SIB1_ssb_PeriodicityServingCell = 5; + SIB1_ss_PBCH_BlockPower = -60; + absoluteFrequencySSB = 0; + DL_FreqBandIndicatorNR = 15; + DL_absoluteFrequencyPointA = 15; + DL_offsetToCarrier = 15; + DL_SCS_SubcarrierSpacing = "kHz30"; + DL_SCS_SpecificCarrier_k0 = 0; + DL_carrierBandwidth = 15; + DL_locationAndBandwidth = 15; + DL_BWP_SubcarrierSpacing = "kHz30"; + DL_BWP_prefix_type = "NORMAL"; + UL_FreqBandIndicatorNR = 15; + UL_absoluteFrequencyPointA = 13; + UL_additionalSpectrumEmission = 3; + UL_p_Max = -1; + UL_frequencyShift7p5khz = "TRUE"; + UL_offsetToCarrier = 10; + UL_SCS_SubcarrierSpacing = "kHz30"; + UL_SCS_SpecificCarrier_k0 = 0; + UL_carrierBandwidth = 15; + UL_locationAndBandwidth = 15; + UL_BWP_SubcarrierSpacing = "kHz30"; + UL_BWP_prefix_type = "NORMAL"; + UL_timeAlignmentTimerCommon = "infinity"; + ServingCellConfigCommon_n_TimingAdvanceOffset = "n0" + ServingCellConfigCommon_ssb_PositionsInBurst_PR = 0x01; + ServingCellConfigCommon_ssb_periodicityServingCell = 10; + ServingCellConfigCommon_dmrs_TypeA_Position = 2; + NIA_SubcarrierSpacing = "kHz15"; + ServingCellConfigCommon_ss_PBCH_BlockPower = -60; + referenceSubcarrierSpacing = "kHz15"; + dl_UL_TransmissionPeriodicity = "ms0p5"; + nrofDownlinkSlots = 10; + nrofDownlinkSymbols = 10; + nrofUplinkSlots = 10; + nrofUplinkSymbols = 10; + rach_totalNumberOfRA_Preambles = 63; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_choice = "oneEighth"; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneEighth = 4; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneFourth = 8; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_oneHalf = 16; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_one = 24; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_two = 32; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_four = 8; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_eight = 4; + rach_ssb_perRACH_OccasionAndCB_PreamblesPerSSB_sixteen = 2; + rach_groupBconfigured = "ENABLE"; + rach_ra_Msg3SizeGroupA = 56; + rach_messagePowerOffsetGroupB = "dB0"; + rach_numberOfRA_PreamblesGroupA = 32; + rach_ra_ContentionResolutionTimer = 8; + rsrp_ThresholdSSB = 64; + rsrp_ThresholdSSB_SUL = 64; + prach_RootSequenceIndex_choice = "l839"; + prach_RootSequenceIndex_l839 = 0; + prach_RootSequenceIndex_l139 = 0; + prach_msg1_SubcarrierSpacing = "kHz30"; + restrictedSetConfig = "unrestrictedSet"; + msg3_transformPrecoding = "ENABLE"; + prach_ConfigurationIndex = 10; + prach_msg1_FDM = "one"; + prach_msg1_FrequencyStart = 10; + zeroCorrelationZoneConfig = 10; + preambleReceivedTargetPower = -150; + preambleTransMax = 6; + powerRampingStep = "dB0"; + ra_ResponseWindow = 8; + groupHoppingEnabledTransformPrecoding = "ENABLE"; + msg3_DeltaPreamble = 0; + p0_NominalWithGrant = 0; + PUSCH_TimeDomainResourceAllocation_k2 = 0; + PUSCH_TimeDomainResourceAllocation_mappingType = "typeA"; + PUSCH_TimeDomainResourceAllocation_startSymbolAndLength = 0; + pucch_ResourceCommon = 0; + pucch_GroupHopping = "neither"; + hoppingId = 0; + p0_nominal = -30; + PDSCH_TimeDomainResourceAllocation_k0 = 2; + PDSCH_TimeDomainResourceAllocation_mappingType = "typeA"; + PDSCH_TimeDomainResourceAllocation_startSymbolAndLength = 0; + rateMatchPatternId = 0; + RateMatchPattern_patternType = "bitmaps"; + symbolsInResourceBlock = "oneSlot"; + periodicityAndPattern = 2; + RateMatchPattern_controlResourceSet = 5; + RateMatchPattern_subcarrierSpacing = "kHz30"; + RateMatchPattern_mode = "dynamic"; + controlResourceSetZero = 0; + searchSpaceZero = 0; + searchSpaceSIB1 = 10; + searchSpaceOtherSystemInformation = 10; + pagingSearchSpace = 10; + ra_SearchSpace = 10; + PDCCH_common_controlResourceSetId = 5; + PDCCH_common_ControlResourceSet_duration = 2; + PDCCH_cce_REG_MappingType = "nonInterleaved"; + PDCCH_reg_BundleSize = 3; + PDCCH_interleaverSize = 3; + PDCCH_shiftIndex = 10; + PDCCH_precoderGranularity = "sameAsREG-bundle"; + PDCCH_TCI_StateId = 32; + tci_PresentInDCI = "ENABLE"; + PDCCH_DMRS_ScramblingID = 0; + SearchSpaceId = 10; + commonSearchSpaces_controlResourceSetId = 5; + SearchSpace_monitoringSlotPeriodicityAndOffset_choice = "sl1"; + SearchSpace_monitoringSlotPeriodicityAndOffset_value = 0; + SearchSpace_duration = 2; + SearchSpace_nrofCandidates_aggregationLevel1 = 0; + SearchSpace_nrofCandidates_aggregationLevel2 = 0; + SearchSpace_nrofCandidates_aggregationLevel4 = 0; + SearchSpace_nrofCandidates_aggregationLevel8 = 0; + SearchSpace_nrofCandidates_aggregationLevel16 = 0; + SearchSpace_searchSpaceType = "common"; + Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel1 = 1; + Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel2 = 1; + Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel4 = 1; + Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel8 = 1; + Common_dci_Format2_0_nrofCandidates_SFI_aggregationLevel16 = 1; + Common_dci_Format2_3_monitoringPeriodicity = 1; + Common_dci_Format2_3_nrofPDCCH_Candidates = 1; + ue_Specific__dci_Formats = "formats0-0-And-1-0"; + RateMatchPatternLTE_CRS_carrierFreqDL = 6; + RateMatchPatternLTE_CRS_carrierBandwidthDL = 6; + RateMatchPatternLTE_CRS_nrofCRS_Ports = 1; + RateMatchPatternLTE_CRS_v_Shift = 0; + RateMatchPatternLTE_CRS_radioframeAllocationPeriod = 1; + RateMatchPatternLTE_CRS_radioframeAllocationOffset = 0; + RateMatchPatternLTE_CRS_subframeAllocation_choice = "oneFrame"; + } + ); + + + srb1_parameters : + { + # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] + timer_poll_retransmit = 80; + + # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] + timer_reordering = 35; + + # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] + timer_status_prohibit = 0; + + # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] + poll_pdu = 4; + + # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] + poll_byte = 99999; + + # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] + max_retx_threshold = 4; + } + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// MME parameters: + mme_ip_address = ( { ipv4 = "192.168.12.26"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + NETWORK_INTERFACES : + { + + GNB_INTERFACE_NAME_FOR_S1_MME = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.111/24"; + GNB_INTERFACE_NAME_FOR_S1U = "eth0"; + GNB_IPV4_ADDRESS_FOR_S1U = "192.168.12.111/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + } +); + +L1s = ( + { + num_cc = 1; + tr_n_preference = "local_mac"; + } +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [7]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + sdr_addrs = "addr=192.168.20.2,second_addr=192.168.10.2,mgmt_addr=192.168.20.2,clock_source=external,time_source=external"; + + } +); + +THREAD_STRUCT = ( + { + #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" + parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; + #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" + worker_config = "WORKER_ENABLE"; + } +); + +NETWORK_CONTROLLER : +{ + FLEXRAN_ENABLED = "no"; + FLEXRAN_INTERFACE_NAME = "lo"; + FLEXRAN_IPV4_ADDRESS = "127.0.0.1"; + FLEXRAN_PORT = 2210; + FLEXRAN_CACHE = "/mnt/oai_agent_cache"; + FLEXRAN_AWAIT_RECONF = "no"; +}; + + log_config : + { + global_log_level ="info"; + global_log_verbosity ="medium"; + hw_log_level ="info"; + hw_log_verbosity ="medium"; + phy_log_level ="info"; + phy_log_verbosity ="medium"; + mac_log_level ="info"; + mac_log_verbosity ="high"; + rlc_log_level ="info"; + rlc_log_verbosity ="medium"; + pdcp_log_level ="info"; + pdcp_log_verbosity ="medium"; + rrc_log_level ="info"; + rrc_log_verbosity ="medium"; + }; + diff --git a/ci-scripts/main.py b/ci-scripts/main.py index cb9f9a3b0d59ea8e83664d6d6026b55a579812fd..5577f707fb7a3f620a3c3dc2ade58b9883719f6b 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -1,3 +1,5 @@ +# dummy commit +#/* # * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more # * contributor license agreements. See the NOTICE file distributed with # * this work for additional information regarding copyright ownership. @@ -42,6 +44,9 @@ ENB_PROCESS_SEG_FAULT = -11 ENB_PROCESS_ASSERTION = -12 ENB_PROCESS_REALTIME_ISSUE = -13 ENB_PROCESS_NOLOGFILE_TO_ANALYZE = -14 +UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 +UE_PROCESS_COULD_NOT_SYNC = -21 +UE_PROCESS_ASSERTION = -22 HSS_PROCESS_FAILED = -2 HSS_PROCESS_OK = +2 MME_PROCESS_FAILED = -3 @@ -49,11 +54,8 @@ MME_PROCESS_OK = +3 SPGW_PROCESS_FAILED = -4 SPGW_PROCESS_OK = +4 UE_IP_ADDRESS_ISSUE = -5 -OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE = -20 -OAI_UE_PROCESS_COULD_NOT_SYNC = -21 -OAI_UE_PROCESS_ASSERTION = -22 -OAI_UE_PROCESS_FAILED = -6 -OAI_UE_PROCESS_OK = +6 +UE_PROCESS_FAILED = -6 +UE_PROCESS_OK = +6 #----------------------------------------------------------- # Import @@ -68,6 +70,7 @@ import xml.etree.ElementTree as ET import logging import datetime import signal +#import platform from multiprocessing import Process, Lock, SimpleQueue logging.basicConfig( level=logging.DEBUG, @@ -103,6 +106,7 @@ class SSHConnection(): self.desc = '' self.Build_eNB_args = '' self.Initialize_eNB_args = '' + self.air_interface = 'lte' self.eNBLogFile = '' self.eNB_instance = '' self.eNBOptions = '' @@ -140,11 +144,14 @@ class SSHConnection(): self.UEUserName = '' self.UEPassword = '' self.UE_instance = '' - self.UESourceCodePath = '' self.UELogFile = '' + self.UESourceCodePath = '' self.Build_OAI_UE_args = '' self.Initialize_OAI_UE_args = '' - + self.Initialize_OAI_eNB_args = '' + self.clean_repository = True + self.eNBOsVersion = '' + def open(self, ipaddress, username, password): count = 0 connect_status = False @@ -339,8 +346,6 @@ class SSHConnection(): self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) self.command('mv compile_oai_enb.log ' + 'build_log_' + self.testCase_id, '\$', 5) - # Workaround to run with develop-nr - self.command('if [ -e ran_build ]; then cp -rf ran_build lte_build_oai; fi', '\$', 30) self.close() self.CreateHtmlTestRow(self.Build_eNB_args, 'OK', ALL_PROCESSES_OK) @@ -355,7 +360,9 @@ class SSHConnection(): # here add a check if git clone or git fetch went smoothly self.command('git config user.email "jenkins@openairinterface.org"', '\$', 5) self.command('git config user.name "OAI Jenkins"', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) + if self.clean_repository: + pass + self.command('echo ' + self.UEPassword + ' | sudo -S git clean -x -d -ff', '\$', 30) # if the commit ID is provided use it to point to it if self.eNBCommitID != '': self.command('git checkout -f ' + self.eNBCommitID, '\$', 5) @@ -373,7 +380,7 @@ class SSHConnection(): self.command('mkdir -p log', '\$', 5) self.command('chmod 777 log', '\$', 5) # no need to remove in log (git clean did the trick) - self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee compile_oai_ue.log', 'Bypassing the Tests', 600) + self.command('stdbuf -o0 ./build_oai ' + self.Build_OAI_UE_args + ' 2>&1 | stdbuf -o0 tee -a compile_oai_ue.log', 'Bypassing the Tests', 600) self.command('mkdir -p build_log_' + self.testCase_id, '\$', 5) self.command('mv log/* ' + 'build_log_' + self.testCase_id, '\$', 5) self.command('mv compile_oai_ue.log ' + 'build_log_' + self.testCase_id, '\$', 5) @@ -492,13 +499,13 @@ class SSHConnection(): # do not reset board twice in IF4.5 case result = re.search('rru|enb|du', str(config_file)) if result is not None: - self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 10) + self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 30) result = re.search('type: b200', str(self.ssh.before)) if result is not None: logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + self.eNBPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + self.command('echo ' + self.eNBPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 5) # Reloading FGPA bin firmware - self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 15) + self.command('echo ' + self.eNBPassword + ' | sudo -S uhd_find_devices', '\$', 30) # Make a copy and adapt to EPC / eNB IP addresses self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) self.command('sed -i -e \'s/CI_MME_IP_ADDR/' + self.EPCIPAddress + '/\' ' + ci_full_config_file, '\$', 2); @@ -506,10 +513,16 @@ class SSHConnection(): # Launch eNB with the modified config file self.command('source oaienv', '\$', 5) self.command('cd cmake_targets', '\$', 5) - self.command('echo "ulimit -c unlimited && ./lte_build_oai/build/lte-softmodem -O ' + self.eNBSourceCodePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + self.eNBPassword + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + self.eNBSourceCodePath + '/cmake_targets -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo "ulimit -c unlimited && ./ran_build/build/' + self.air_interface + '-softmodem -O ' + self.eNBSourceCodePath + '/' + ci_full_config_file + extra_options + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh ', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh ', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) + #use nohup instead of daemon + #self.command('echo ' + self.eNBPassword + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + self.eNBSourceCodePath + '/cmake_targets -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh' + ' > ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log' + ' 2>&1 &', self.eNBUserName, 5) if not rruCheck: self.eNBLogFile = 'enb_' + self.testCase_id + '.log' if extra_options != '': @@ -600,120 +613,160 @@ class SSHConnection(): if self.UEIPAddress == '' or self.UEUserName == '' or self.UEPassword == '' or self.UESourceCodePath == '': Usage() sys.exit('Insufficient Parameter') - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - check_eNB = True - check_OAI_UE = False - pStatus = self.CheckProcessExist(check_eNB, check_OAI_UE) - if (pStatus < 0): - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) - self.CreateHtmlTabFooter(False) - sys.exit(1) + #initialize_OAI_UE_flag = True + #pStatus = self.CheckOAIUEProcessExist(initialize_OAI_UE_flag) + #if (pStatus < 0): + # self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', pStatus) + # self.CreateHtmlTabFooter(False) + # sys.exit(1) self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) # b2xx_fx3_utils reset procedure - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 10) - result = re.search('type: b200', str(self.ssh.before)) + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) + result = re.search('type: n3xx', str(self.ssh.before)) if result is not None: + pass logging.debug('Found a B2xx device --> resetting it') - self.command('echo ' + self.UEPassword + ' | sudo -S b2xx_fx3_utils --reset-device', '\$', 10) + self.command('echo ' + self.UEPassword + ' | sudo -S sudo b2xx_fx3_utils --reset-device', '\$', 5) # Reloading FGPA bin firmware - self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 15) + self.command('echo ' + self.UEPassword + ' | sudo -S uhd_find_devices', '\$', 30) else: logging.debug('Did not find any B2xx device') self.command('cd ' + self.UESourceCodePath, '\$', 5) + # Initialize_OAI_UE_args usually start with -C and followed by the location in repository self.command('source oaienv', '\$', 5) - self.command('cd cmake_targets/lte_build_oai/build', '\$', 5) - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - # We may have to regenerate the .u* files - if result is None: - self.command('sed -e "s#93#92#" -e "s#8baf473f2f8fd09487cccbd7097c6862#fec86ba6eb707ed08905757b1bb44b8f#" -e "s#e734f8734007d6c5ce7a0508809e7e9c#C42449363BBAD02B66D16BC975D77CC1#" ../../../openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf > ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf .u*', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S ../../../targets/bin/conf2uedata -c ../../../openair3/NAS/TOOLS/ci-ue_eurecom_test_sfr.conf -o .', '\$', 5) - # Launch UE with the modified config file - self.command('echo "ulimit -c unlimited && ./lte-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('cd cmake_targets/ran_build/build', '\$', 5) + self.command('echo "ulimit -c unlimited && ./'+ self.air_interface +'-uesoftmodem ' + self.Initialize_OAI_UE_args + '" > ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) self.command('chmod 775 ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) + #use nohup instead of daemon + self.command('echo $USER; nohup sudo ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh' + ' > ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ' + ' 2>&1 &', self.UEUserName, 5) + #self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/ran_build/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) self.UELogFile = 'ue_' + self.testCase_id + '.log' - - # We are now looping several times to hope we really sync w/ an eNB - doOutterLoop = True - outterLoopCounter = 5 - gotSyncStatus = True - fullSyncStatus = True - while (doOutterLoop): - self.command('cd ' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S rm -Rf ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log', '\$', 5) - self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/lte_build_oai/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) - time.sleep(6) - self.command('cd ../..', '\$', 5) - doLoop = True - loopCounter = 10 - gotSyncStatus = True - # the 'got sync' message is for the UE threads synchronization - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here should never occur - logging.error('"got sync" message never showed!') - gotSyncStatus = False - doLoop = False - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('got sync', str(self.ssh.before)) - if result is None: - time.sleep(6) + time.sleep(6) + self.command('cd ../..', '\$', 5) + doLoop = True + loopCounter = 10 + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + self.close() + doLoop = False + logging.error('\u001B[1;37;41m UE logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'KO', ALL_PROCESSES_OK, 'OAI UE') + self.CreateHtmlTabFooter(False) + sys.exit(1) + else: + self.command('stdbuf -o0 cat ' + self.UELogFile + ' | egrep --text --color=never -i "wait|sync"', '\$', 4) + if self.air_interface == 'nr': + result = re.search('Starting sync detection', str(self.ssh.before)) else: - doLoop = False - logging.debug('Found "got sync" message!') - if gotSyncStatus == False: - # we certainly need to stop the lte-uesoftmodem process if it is still running! - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - time.sleep(3) - # We are now checking if sync w/ eNB DOES NOT OCCUR - # Usually during the cell synchronization stage, the UE returns with No cell synchronization message - doLoop = True - loopCounter = 10 - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # Here we do have a great chance that the UE did cell-sync w/ eNB - doLoop = False - doOutterLoop = False - fullSyncStatus = True - continue - self.command('stdbuf -o0 cat ue_' + self.testCase_id + '.log | egrep --text --color=never -i "wait|sync"', '\$', 4) - result = re.search('No cell synchronization found', str(self.ssh.before)) + result = re.search('got sync', str(self.ssh.before)) if result is None: - time.sleep(6) + time.sleep(10) else: doLoop = False - fullSyncStatus = False - logging.debug('Found: "No cell synchronization" message! --> try again') - time.sleep(6) - self.command('ps -aux | grep --text --color=never softmodem | grep -v grep', '\$', 4) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) - if result is not None: - self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal=SIGINT lte-uesoftmodem', '\$', 4) - outterLoopCounter = outterLoopCounter - 1 - if (outterLoopCounter == 0): - doOutterLoop = False + self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') + logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') + self.close() - if fullSyncStatus and gotSyncStatus: - result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) - if result is None: - self.command('ifconfig oaitun_ue1', '\$', 4) - result = re.search('inet addr', str(self.ssh.before)) - if result is not None: - logging.debug('\u001B[1m oaitun_ue1 interface is mounted and configured\u001B[0m') + def InitializeOAIeNB(self): + if self.eNBIPAddress == '' or self.eNBUserName == '' or self.eNBPassword == '' or self.eNBSourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + #initialize_OAI_eNB_flag = True + #pStatus = self.CheckOAIeNBProcessExist(initialize_OAI_eNB_flag) + #if (pStatus < 0): + # self.CreateHtmlTestRow(self.Initialize_OAI_eNB_args, 'KO', pStatus) + # self.CreateHtmlTabFooter(False) + # sys.exit(1) + self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) + self.command('cd ' + self.eNBSourceCodePath, '\$', 5) + # Initialize_OAI_eNB_args usually start with -C and followed by the location in repository + #full_config_file = self.Initialize_OAI_eNB_args.replace('-O ','') + #extIdx = full_config_file.find('.conf') + #if (extIdx > 0): + # extra_options = full_config_file[extIdx + 5:] + # # if tracer options is on, compiling and running T Tracer + # result = re.search('T_stdout', str(extra_options)) + ## if result is not None: + # logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') + # self.command('cd common/utils/T/tracer', '\$', 5) + # self.command('make', '\$', 10) + # self.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', self.eNBUserName, 5) + # self.command('cd ' + self.eNBSourceCodePath, '\$', 5) + # full_config_file = full_config_file[:extIdx + 5] + # config_path, config_file = os.path.split(full_config_file) + #ci_full_config_file = config_path + '/ci-' + config_file + #rruCheck = False + #result = re.search('rru', str(config_file)) + #if result is not None: + # rruCheck = True + ## Make a copy and adapt to EPC / eNB IP addresses + #self.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) + #self.command('sed -i -e \'s/CI_eNB_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); + # Launch eNB with the modified config file + self.command('source oaienv', '\$', 5) + self.command('cd cmake_targets/ran_build/build', '\$', 5) + #self.command('echo "ulimit -c unlimited && ./' + self.air_interface + '-softmodem ' + self.Initialize_OAI_eNB_args + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.eNBLogFile = 'enb_' + self.testCase_id + '.log' + self.command('echo "ulimit -c unlimited && ./' + self.air_interface + '-softmodem ' + self.Initialize_OAI_eNB_args + '|& tee ' + self.eNBSourceCodePath + '/cmake_targets/' + self.eNBLogFile + '" > ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S rm -Rf ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log', '\$', 5) + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) + #use nohup instead of daemon + self.command('echo $USER; nohup sudo ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh' + ' > ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log' + ' 2>&1 &', self.eNBUserName, 5) + #self.command('echo ' + self.eNBPassword + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + self.eNBSourceCodePath + '/cmake_targets/ran_build/build -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + time.sleep(6) + self.command('cd ../..', '\$', 5) + doLoop = True + loopCounter = 10 + print('gNB log file: ' + self.eNBLogFile) + while (doLoop): + loopCounter = loopCounter - 1 + if (loopCounter == 0): + # In case of T tracer recording, we may need to kill it + #result = re.search('T_stdout', str(self.Initialize_OAI_eNB_args)) + #if result is not None: + # self.command('killall --signal SIGKILL record', '\$', 5) + self.close() + doLoop = False + logging.error('\u001B[1;37;41m eNB logging system did not show got sync! \u001B[0m') + self.CreateHtmlTestRow(self.Initialize_OAI_eNB_args, 'KO', ALL_PROCESSES_OK, 'OAI eNB') + self.CreateHtmlTabFooter(False) + ## In case of T tracer recording, we need to kill tshark on EPC side + #result = re.search('T_stdout', str(self.Initialize_OAI_eNB_args)) + #if result is not None: + # self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) + # logging.debug('\u001B[1m Stopping tshark \u001B[0m') + # self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) + # self.close() + # time.sleep(1) + # pcap_log_file = 'enb_' + self.testCase_id + '_s1log.pcap' + # copyin_res = self.copyin(self.EPCIPAddress, self.EPCUserName, self.EPCPassword, '/tmp/' + pcap_log_file, '.') + # if (copyin_res == 0): + # self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, pcap_log_file, self.eNBSourceCodePath + '/cmake_targets/.') + sys.exit(1) + else: + #print('current directory: ' + os.getcwd()) + #self.command('pwd', '\$', 4) + #print('self.command pwd: ' + str(self.ssh.before)) + self.command('stdbuf -o0 cat ' + self.eNBLogFile + ' | egrep --text --color=never -i "wait|sync"', '\$', 30) + #print(self.ssh.before) + result = re.search('got sync', str(self.ssh.before)) + if result is None: + time.sleep(11) else: - logging.error('\u001B[1m oaitun_ue1 interface is either NOT mounted or NOT configured\u001B[0m') - + doLoop = False + self.CreateHtmlTestRow(self.Initialize_OAI_eNB_args, 'OK', ALL_PROCESSES_OK, 'OAI eNB') + logging.debug('\u001B[1m Initialize OAI eNB Completed\u001B[0m') self.close() - # For the moment we are always OK!!! - self.CreateHtmlTestRow(self.Initialize_OAI_UE_args, 'OK', ALL_PROCESSES_OK, 'OAI UE') - logging.debug('\u001B[1m Initialize OAI UE Completed\u001B[0m') def checkDevTTYisUnlocked(self): self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword) @@ -886,7 +939,7 @@ class SSHConnection(): return ping_time = re.findall("-c (\d+)",str(self.ping_args)) device_id = 'catm' - ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) + ping_status = self.command('stdbuf -o0 ping ' + self.ping_args + ' ' + str(moduleIPAddr) + ' 2>&1 | stdbuf -o0 tee -a ping_' + self.testCase_id + '_' + device_id + '.log', '\$', int(ping_time[0])*1.5) # TIMEOUT CASE if ping_status < 0: message = 'Ping with UE (' + str(moduleIPAddr) + ') crashed due to TIMEOUT!' @@ -2165,7 +2218,7 @@ class SSHConnection(): status = status_queue.get() if (status < 0): result = status - if result == OAI_UE_PROCESS_FAILED: + if result == UE_PROCESS_FAILED: fileCheck = re.search('ue_', str(self.UELogFile)) if fileCheck is not None: self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') @@ -2177,13 +2230,13 @@ class SSHConnection(): def CheckOAIUEProcess(self, status_queue): try: self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-uesoftmodem', str(self.ssh.before)) + self.command('stdbuf -o0 ps -aux | grep -v grep | grep --color=never ' + self.air_interface + '-uesoftmodem', '\$', 5) + result = re.search(self.air_interface + '-uesoftmodem', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m OAI UE Process Not Found! \u001B[0m') - status_queue.put(OAI_UE_PROCESS_FAILED) + status_queue.put(UE_PROCESS_FAILED) else: - status_queue.put(OAI_UE_PROCESS_OK) + status_queue.put(UE_PROCESS_OK) self.close() except: os.kill(os.getppid(),signal.SIGUSR1) @@ -2191,8 +2244,8 @@ class SSHConnection(): def CheckeNBProcess(self, status_queue): try: self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) - result = re.search('lte-softmodem', str(self.ssh.before)) + self.command('stdbuf -o0 ps -aux | grep -v grep | grep --color=never ' + self.air_interface + '-softmodem', '\$', 5) + result = re.search(self.air_interface + '-softmodem', str(self.ssh.before)) if result is None: logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') status_queue.put(ENB_PROCESS_FAILED) @@ -2418,12 +2471,16 @@ class SSHConnection(): if (not os.path.isfile('./' + UElogFile)): return -1 ue_log_file = open('./' + UElogFile, 'r') +<<<<<<< HEAD exitSignalReceived = False +======= +>>>>>>> origin/develop-nr foundAssertion = False msgAssertion = '' msgLine = 0 foundSegFault = False foundRealTimeIssue = False +<<<<<<< HEAD uciStatMsgCount = 0 pdcpDataReqFailedCount = 0 badDciCount = 0 @@ -2448,11 +2505,35 @@ class SSHConnection(): foundAssertion = True result = re.search('LLL', str(line)) if result is not None and not exitSignalReceived: +======= + rlcDiscardBuffer = 0 + rachCanceledProcedure = 0 + uciStatMsgCount = 0 + pdcpFailure = 0 + ulschFailure = 0 + no_cell_sync_found = False + mib_found = False + frequency_found = False + self.htmlUEFailureMsg = '' + for line in ue_log_file.readlines(): + result = re.search('[Ss]egmentation [Ff]ault', str(line)) + if result is not None: + foundSegFault = True + result = re.search('[Cc]ore [dD]ump', str(line)) + if result is not None: + foundSegFault = True + result = re.search('[Aa]ssertion', str(line)) + if result is not None: + foundAssertion = True + result = re.search('LLL', str(line)) + if result is not None: +>>>>>>> origin/develop-nr foundRealTimeIssue = True if foundAssertion and (msgLine < 3): msgLine += 1 msgAssertion += str(line) result = re.search('uci->stat', str(line)) +<<<<<<< HEAD if result is not None and not exitSignalReceived: uciStatMsgCount += 1 result = re.search('PDCP data request failed', str(line)) @@ -2464,6 +2545,10 @@ class SSHConnection(): result = re.search('Generating RRCConnectionReconfigurationComplete', str(line)) if result is not None: rrcConnectionRecfgComplete += 1 +======= + if result is not None: + uciStatMsgCount += 1 +>>>>>>> origin/develop-nr # No cell synchronization found, abandoning result = re.search('No cell synchronization found, abandoning', str(line)) if result is not None: @@ -2501,6 +2586,7 @@ class SSHConnection(): frequency_found = True except Exception as e: logging.error('\033[91m' + "Measured Carrier Frequency not found" + '\033[0m') +<<<<<<< HEAD result = re.search("PLMN MCC (?P<mcc>\d{1,3}), MNC (?P<mnc>\d{1,3}), TAC", str(line)) if result is not None and (not plmn_found): try: @@ -2510,6 +2596,8 @@ class SSHConnection(): plmn_found = True except Exception as e: logging.error('\033[91m' + "PLMN not found" + '\033[0m') +======= +>>>>>>> origin/develop-nr result = re.search("Found (?P<operator>[\w,\s]{1,15}) \(name from internal table\)", str(line)) if result is not None: try: @@ -2545,14 +2633,18 @@ class SSHConnection(): except Exception as e: logging.error('\033[91m' + " AllowedMeasBandwidth not found" + '\033[0m') ue_log_file.close() +<<<<<<< HEAD if rrcConnectionRecfgComplete > 0: statMsg = 'UE connected to eNB (' + str(rrcConnectionRecfgComplete) + ' RRCConnectionReconfigurationComplete message(s) generated)' logging.debug('\033[94m' + statMsg + '\033[0m') self.htmlUEFailureMsg += statMsg + '\n' +======= +>>>>>>> origin/develop-nr if uciStatMsgCount > 0: statMsg = 'UE showed ' + str(uciStatMsgCount) + ' "uci->stat" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmlUEFailureMsg += statMsg + '\n' +<<<<<<< HEAD if pdcpDataReqFailedCount > 0: statMsg = 'UE showed ' + str(pdcpDataReqFailedCount) + ' "PDCP data request failed" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') @@ -2561,14 +2653,30 @@ class SSHConnection(): statMsg = 'UE showed ' + str(badDciCount) + ' "bad DCI 1A" message(s)' logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') self.htmlUEFailureMsg += statMsg + '\n' +======= + if pdcpFailure > 0: + statMsg = 'UE showed ' + str(pdcpFailure) + ' "PDCP Out of Resources" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if ulschFailure > 0: + statMsg = 'UE showed ' + str(ulschFailure) + ' "ULSCH in error in round" message(s)' + logging.debug('\u001B[1;30;43m ' + statMsg + ' \u001B[0m') + self.htmlUEFailureMsg += statMsg + '\n' + if rachCanceledProcedure > 0: + rachMsg = 'UE cancelled ' + str(rachCanceledProcedure) + ' RA procedure(s)' + logging.debug('\u001B[1;30;43m ' + rachMsg + ' \u001B[0m') + self.htmlUEFailureMsg += rachMsg + '\n' +>>>>>>> origin/develop-nr if foundSegFault: logging.debug('\u001B[1;37;41m UE ended with a Segmentation Fault! \u001B[0m') return ENB_PROCESS_SEG_FAULT if foundAssertion: - logging.debug('\u001B[1;30;43m UE showed an assertion! \u001B[0m') - self.htmlUEFailureMsg += 'UE showed an assertion!\n' + logging.debug('\u001B[1;37;43m UE ended with an assertion! \u001B[0m') + # removed for esthetics + #self.htmlUEFailureMsg += msgAssertion + self.htmlUEFailureMsg += 'UE ended with an assertion!\n' if not mib_found or not frequency_found: - return OAI_UE_PROCESS_ASSERTION + return UE_PROCESS_ASSERTION if foundRealTimeIssue: logging.debug('\u001B[1;37;41m UE faced real time issues! \u001B[0m') self.htmlUEFailureMsg += 'UE faced real time issues!\n' @@ -2576,17 +2684,42 @@ class SSHConnection(): if no_cell_sync_found and not mib_found: logging.debug('\u001B[1;37;41m UE could not synchronize ! \u001B[0m') self.htmlUEFailureMsg += 'UE could not synchronize!\n' - return OAI_UE_PROCESS_COULD_NOT_SYNC +<<<<<<< HEAD + return UE_PROCESS_COULD_NOT_SYNC +======= + return UE_PROCESS_COULD_NOT_SYNC + if rlcDiscardBuffer > 0: + rlcMsg = 'UE RLC discarded ' + str(rlcDiscardBuffer) + ' buffer(s)' + logging.debug('\u001B[1;37;41m ' + rlcMsg + ' \u001B[0m') + self.htmlUEFailureMsg += rlcMsg + '\n' + return ENB_PROCESS_REALTIME_ISSUE +>>>>>>> origin/develop-nr return 0 def TerminateeNB(self): self.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) self.command('cd ' + self.eNBSourceCodePath + '/cmake_targets', '\$', 5) +<<<<<<< HEAD self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-softmodem', str(self.ssh.before)) if result is not None: self.command('echo ' + self.eNBPassword + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) self.command('echo ' + self.eNBPassword + ' | sudo -S killall --signal SIGINT lte-softmodem || true', '\$', 5) +======= + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) + #use nohup instead of daemon + self.command('echo ' + self.eNBPassword + ' | sudo -S daemon --name=enb' + str(self.eNB_instance) + '_daemon --stop', '\$', 5) + self.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) + self.command('echo ' + self.eNBPassword + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) + time.sleep(5) + self.command('stdbuf -o0 ps -aux | grep softmodem | grep -v grep', '\$', 5) + result = re.search('-softmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.eNBPassword + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) +>>>>>>> origin/develop-nr time.sleep(5) self.command('stdbuf -o0 ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-softmodem', str(self.ssh.before)) @@ -2667,6 +2800,10 @@ class SSHConnection(): self.command('cd ' + self.EPCSourceCodePath, '\$', 5) self.command('cd scripts', '\$', 5) self.command('rm -f ./kill_hss.sh', '\$', 5) + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) self.command('echo ' + self.EPCPassword + ' | sudo -S daemon --name=simulated_hss --stop', '\$', 5) time.sleep(1) self.command('echo ' + self.EPCPassword + ' | sudo -S killall --signal SIGKILL hss_sim', '\$', 5) @@ -2734,6 +2871,7 @@ class SSHConnection(): def TerminateOAIUE(self): self.open(self.UEIPAddress, self.UEUserName, self.UEPassword) self.command('cd ' + self.UESourceCodePath + '/cmake_targets', '\$', 5) +<<<<<<< HEAD self.command('ps -aux | grep --color=never softmodem | grep -v grep', '\$', 5) result = re.search('lte-uesoftmodem', str(self.ssh.before)) if result is not None: @@ -2746,18 +2884,39 @@ class SSHConnection(): self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL lte-uesoftmodem || true', '\$', 5) time.sleep(2) self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) +======= + #to use daemon on CentOS we need to source the function + #linux_distro = platform.linux_distribution()[0] + #if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE): + #self.command('source /etc/init.d/functions', '\$', 5) + #self.command('echo ' + self.UEPassword + ' | sudo -S daemon --name=ue' + str(self.UE_instance) + '_daemon --stop', '\$', 5) + self.command('rm -f my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5) + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGINT -r .*-uesoftmodem || true', '\$', 5) + time.sleep(5) + self.command('stdbuf -o0 ps -aux | grep uesoftmodem | grep -v grep', '\$', 5) + result = re.search('-uesoftmodem', str(self.ssh.before)) + if result is not None: + self.command('echo ' + self.UEPassword + ' | sudo -S killall --signal SIGKILL -r .*-uesoftmodem || true', '\$', 5) + time.sleep(5) +>>>>>>> origin/develop-nr self.close() result = re.search('ue_', str(self.UELogFile)) if result is not None: copyin_res = self.copyin(self.UEIPAddress, self.UEUserName, self.UEPassword, self.UESourceCodePath + '/cmake_targets/' + self.UELogFile, '.') if (copyin_res == -1): logging.debug('\u001B[1;37;41m Could not copy UE logfile to analyze it! \u001B[0m') +<<<<<<< HEAD self.htmlUEFailureMsg = 'Could not copy UE logfile to analyze it!' - self.CreateHtmlTestRow('N/A', 'KO', OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') + self.CreateHtmlTestRow('N/A', 'KO', UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') +======= + optionsMsg = '<pre style="background-color:white">Could not copy UE logfile to analyze it!</pre>' + self.CreateHtmlTestRow(optionsMsg, 'KO', UE_PROCESS_NOLOGFILE_TO_ANALYZE, 'UE') +>>>>>>> origin/develop-nr self.UELogFile = '' return logging.debug('\u001B[1m Analyzing UE logfile \u001B[0m') logStatus = self.AnalyzeLogFile_UE(self.UELogFile) +<<<<<<< HEAD result = re.search('--no-L2-connect', str(self.Initialize_OAI_UE_args)) if result is not None: ueAction = 'Sniffing' @@ -2769,7 +2928,7 @@ class SSHConnection(): self.CreateHtmlTestRow('N/A', 'KO', logStatus, 'UE') # In case of sniffing on commercial eNBs we have random results # Not an error then - if (logStatus != OAI_UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): + if (logStatus != UE_PROCESS_COULD_NOT_SYNC) or (ueAction != 'Sniffing'): self.Initialize_OAI_UE_args = '' self.AutoTerminateUEandeNB() self.CreateHtmlTabFooter(False) @@ -2782,6 +2941,23 @@ class SSHConnection(): else: self.htmlUEFailureMsg = 'No Log File to analyze!' self.CreateHtmlTestRow('N/A', 'OK', ALL_PROCESSES_OK) +======= + if (logStatus < 0): + optionsMsg = '<pre style="background-color:white"><b>Sniffing Unsuccessful</b>\n' + optionsMsg += self.htmlUEFailureMsg + optionsMsg += '</pre>' + self.CreateHtmlTestRow(optionsMsg, 'KO', logStatus, 'UE') + self.CreateHtmlTabFooter(False) + sys.exit(1) + else: + optionsMsg = '<pre style="background-color:white"><b>Sniffing Successful</b>\n' + optionsMsg += self.htmlUEFailureMsg + optionsMsg += '</pre>' + self.CreateHtmlTestRow(optionsMsg, 'OK', ALL_PROCESSES_OK) + self.UELogFile = '' + else: + self.CreateHtmlTestRow('<pre style="background-color:white">No Log File to analyze</pre>', 'OK', ALL_PROCESSES_OK) +>>>>>>> origin/develop-nr def AutoTerminateUEandeNB(self): if (self.ADBIPAddress != 'none'): @@ -2839,6 +3015,7 @@ class SSHConnection(): self.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap enb_*txt', '\$', 5) self.close() + def LogCollectPing(self): self.open(self.EPCIPAddress, self.EPCUserName, self.EPCPassword) self.command('cd ' + self.EPCSourceCodePath, '\$', 5) @@ -2914,22 +3091,21 @@ class SSHConnection(): self.CpuNb = '4' self.CpuModel = 'Intel(R) Core(TM) i5-6200U' self.CpuMHz = '2399.996 MHz' - return 0 - if machine == 'eNB': - if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': - IPAddress = self.eNBIPAddress - UserName = self.eNBUserName - Password = self.eNBPassword - else: - return -1 - if machine == 'UE': - if self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': - IPAddress = self.UEIPAddress - UserName = self.UEUserName - Password = self.UEPassword - else: - return -1 - + return + machine = None + if self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != '': + machine = 'eNB' + IPAddress = self.eNBIPAddress + UserName = self.eNBUserName + Password = self.eNBPassword + elif self.UEIPAddress != '' and self.UEUserName != '' and self.UEPassword != '': + machine = 'UE' + IPAddress = self.UEIPAddress + UserName = self.UEUserName + Password = self.UEPassword + if machine is None: + Usage() + sys.exit('Insufficient Parameter') self.open(IPAddress, UserName, Password) self.command('lsb_release -a', '\$', 5) result = re.search('Description:\\\\t(?P<os_type>[a-zA-Z0-9\-\_\.\ ]+)', str(self.ssh.before)) @@ -2946,7 +3122,7 @@ class SSHConnection(): if result is not None: self.UhdVersion = result.group('uhd_version') logging.debug('UHD Version is: ' + self.UhdVersion) - self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 15) + self.command('echo ' + Password + ' | sudo -S uhd_find_devices', '\$', 12) result = re.search('product: (?P<usrp_board>[0-9A-Za-z]+)\\\\r\\\\n', str(self.ssh.before)) if result is not None: self.UsrpBoard = result.group('usrp_board') @@ -3184,19 +3360,17 @@ class SSHConnection(): elif (str(status) == 'KO'): if (processesStatus == 0): self.htmlFile.write(' <td bgcolor = "lightcoral" >' + str(status) + '</td>\n') - elif (processesStatus == ENB_PROCESS_FAILED): - self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - eNB process not found</td>\n') - elif (processesStatus == OAI_UE_PROCESS_FAILED): - self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - OAI UE process not found</td>\n') + elif (processesStatus == ENB_PROCESS_FAILED) or (processesStatus == UE_PROCESS_FAILED): + self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - ' + machine + ' process not found</td>\n') elif (processesStatus == ENB_PROCESS_SEG_FAULT): self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - ' + machine + ' process ended in Segmentation Fault</td>\n') - elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == OAI_UE_PROCESS_ASSERTION): + elif (processesStatus == ENB_PROCESS_ASSERTION) or (processesStatus == UE_PROCESS_ASSERTION): self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - ' + machine + ' process ended in Assertion</td>\n') elif (processesStatus == ENB_PROCESS_REALTIME_ISSUE): self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - ' + machine + ' process faced Real Time issue(s)</td>\n') - elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == OAI_UE_PROCESS_NOLOGFILE_TO_ANALYZE): + elif (processesStatus == ENB_PROCESS_NOLOGFILE_TO_ANALYZE) or (processesStatus == UE_PROCESS_NOLOGFILE_TO_ANALYZE): self.htmlFile.write(' <td bgcolor = "orange" >OK?</td>\n') - elif (processesStatus == OAI_UE_PROCESS_COULD_NOT_SYNC): + elif (processesStatus == UE_PROCESS_COULD_NOT_SYNC): self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - UE could not sync</td>\n') elif (processesStatus == HSS_PROCESS_FAILED): self.htmlFile.write(' <td bgcolor = "lightcoral" >KO - HSS process not found</td>\n') @@ -3311,8 +3485,11 @@ def Usage(): print(' --XMLTestFile=[XML Test File to be run]') print('------------------------------------------------------------') +#def GetModeFromXML(): +# SSH.mode = test.findtext('mode') + def CheckClassValidity(action,id): - if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep': + if action != 'Build_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'Initialize_OAI_eNB' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep': logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action) return False return True @@ -3326,11 +3503,21 @@ def GetParametersFromXML(action): SSH.eNB_instance = test.findtext('eNB_instance') if (SSH.eNB_instance is None): SSH.eNB_instance = '0' - + SSH.air_interface = test.findtext('air_interface') + if (SSH.air_interface is None): + SSH.air_interface = 'lte' + else: + SSH.air_interface = SSH.air_interface.lower() + if action == 'Terminate_eNB': SSH.eNB_instance = test.findtext('eNB_instance') if (SSH.eNB_instance is None): SSH.eNB_instance = '0' + SSH.air_interface = test.findtext('air_interface') + if (SSH.air_interface is None): + SSH.air_interface = 'lte' + else: + SSH.air_interface = SSH.air_interface.lower() if action == 'Attach_UE': nbMaxUEtoAttach = test.findtext('nbMaxUEtoAttach') @@ -3341,12 +3528,33 @@ def GetParametersFromXML(action): if action == 'Build_OAI_UE': SSH.Build_OAI_UE_args = test.findtext('Build_OAI_UE_args') + SSH.clean_repository = test.findtext('clean_repository') + if (SSH.clean_repository == 'false'): + SSH.clean_repository = False + else: + SSH.clean_repository = True if action == 'Initialize_OAI_UE': SSH.Initialize_OAI_UE_args = test.findtext('Initialize_OAI_UE_args') SSH.UE_instance = test.findtext('UE_instance') if (SSH.UE_instance is None): SSH.UE_instance = '0' + SSH.air_interface = test.findtext('air_interface') + if (SSH.air_interface is None): + SSH.air_interface = 'lte' + else: + SSH.air_interface = SSH.air_interface.lower() + + if action == 'Initialize_OAI_eNB': + SSH.Initialize_OAI_eNB_args = test.findtext('Initialize_OAI_eNB_args') + SSH.UE_instance = test.findtext('eNB_instance') + if (SSH.eNB_instance is None): + SSH.eNB_instance = '0' + SSH.air_interface = test.findtext('air_interface') + if (SSH.air_interface is None): + SSH.air_interface = 'lte' + else: + SSH.air_interface = SSH.air_interface.lower() if action == 'Terminate_OAI_UE': SSH.eNB_instance = test.findtext('UE_instance') @@ -3404,6 +3612,9 @@ while len(argvs) > 1: sys.exit(0) elif re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-mode=(.+)$', myArgv, re.IGNORECASE) + #if matchReg and mode is not None: + #print('Warning: the mode is defined in both xml file and command line') + #print('ignoring the mode defined in the xml file') mode = matchReg.group(1) elif re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match('^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) @@ -3557,10 +3768,10 @@ elif re.match('^LogCollectIperf$', mode, re.IGNORECASE): sys.exit('Insufficient Parameter') SSH.LogCollectIperf() elif re.match('^LogCollectOAIUE$', mode, re.IGNORECASE): - if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': - Usage() - sys.exit('Insufficient Parameter') - SSH.LogCollectOAIUE() + if SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == '' or SSH.UESourceCodePath == '': + Usage() + sys.exit('Insufficient Parameter') + SSH.LogCollectOAIUE() elif re.match('^InitiateHtml$', mode, re.IGNORECASE): if (SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == ''): Usage() @@ -3569,9 +3780,11 @@ elif re.match('^InitiateHtml$', mode, re.IGNORECASE): foundCount = 0 while (count < SSH.nbTestXMLfiles): xml_test_file = cwd + "/" + SSH.testXMLfiles[count] - xml_test_file = sys.path[0] + "/" + SSH.testXMLfiles[count] if (os.path.isfile(xml_test_file)): - xmlTree = ET.parse(xml_test_file) + try: + xmlTree = ET.parse(xml_test_file) + except: + print("Error while parsing file: " + xml_test_file) xmlRoot = xmlTree.getroot() SSH.htmlTabRefs.append(xmlRoot.findtext('htmlTabRef',default='test-tab-' + str(count))) SSH.htmlTabNames.append(xmlRoot.findtext('htmlTabName',default='Test-' + str(count))) @@ -3585,10 +3798,17 @@ elif re.match('^FinalizeHtml$', mode, re.IGNORECASE): SSH.CreateHtmlFooter(SSH.finalStatus) elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re.IGNORECASE): if re.match('^TesteNB$', mode, re.IGNORECASE): - if SSH.eNBIPAddress == '' or SSH.eNBRepository == '' or SSH.eNBBranch == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '' or SSH.eNBSourceCodePath == '' or SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': + if (SSH.eNBRepository == '' or SSH.eNBBranch == '' or SSH.eNBSourceCodePath == ''): + Usage() + sys.exit('Insufficient Parameter') + if (SSH.eNBIPAddress == '' or SSH.eNBUserName == '' or SSH.eNBPassword == '') and (SSH.UEIPAddress == '' or SSH.UEUserName == '' or SSH.UEPassword == ''): + Usage() + sys.exit('Insufficient Parameter') + elif SSH.ADBIPAddress == 'none' and SSH.EPCIPAddress == 'none': + pass + elif SSH.EPCIPAddress == '' or SSH.EPCUserName == '' or SSH.EPCPassword == '' or SSH.EPCType == '' or SSH.EPCSourceCodePath == '' or SSH.ADBIPAddress == '' or SSH.ADBUserName == '' or SSH.ADBPassword == '': Usage() sys.exit('Insufficient Parameter') - if (SSH.EPCIPAddress != ''): SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/tcp_iperf_stats.awk", "/tmp") SSH.copyout(SSH.EPCIPAddress, SSH.EPCUserName, SSH.EPCPassword, cwd + "/active_net_interfaces.awk", "/tmp") @@ -3658,6 +3878,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.testCase_id = id SSH.desc = test.findtext('desc') action = test.findtext('class') + mode = test.findtext('mode') if (CheckClassValidity(action, id) == False): continue SSH.ShowTestID() @@ -3686,6 +3907,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re SSH.InitializeOAIUE() elif action == 'Terminate_OAI_UE': SSH.TerminateOAIUE() + elif action == 'Initialize_OAI_eNB': + SSH.InitializeOAIeNB() elif action == 'Initialize_CatM_module': SSH.InitializeCatM() elif action == 'Terminate_CatM_module': diff --git a/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml new file mode 100644 index 0000000000000000000000000000000000000000..f9d068c5b2e377fd369d0047b399d5775b1d13a5 --- /dev/null +++ b/ci-scripts/xml_files/gnb_nr_ue_usrp_run.xml @@ -0,0 +1,64 @@ +<!-- + + Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The OpenAirInterface Software Alliance licenses this file to You under + the OAI Public License, Version 1.1 (the "License"); you may not use this file + except in compliance with the License. + You may obtain a copy of the License at + + http://www.openairinterface.org/?page_id=698 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For more information about the OpenAirInterface (OAI) Software Alliance: + contact@openairinterface.org + +--> +<testCaseList> + <htmlTabRef>run-OAI-gNB-NR-UE-USRP</htmlTabRef> + <htmlTabName>run OAI gNB and OAI NR UE USRP</htmlTabName> + <htmlTabIcon>tasks</htmlTabIcon> + <TestCaseRequestedList> +090101 000001 090102 000001 090108 090109 + </TestCaseRequestedList> + <TestCaseExclusionList></TestCaseExclusionList> + + <testCase id="090101"> + <class>Initialize_OAI_eNB</class> + <desc>Initialize gNB USRP</desc> + <Initialize_OAI_eNB_args>-O ../../../ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf</Initialize_OAI_eNB_args> + <air_interface>NR</air_interface> + </testCase> + + <testCase id="000001"> + <class>IdleSleep</class> + <desc>Sleep</desc> + <idle_sleep_time_in_sec>5</idle_sleep_time_in_sec> + </testCase> + + <testCase id="090102"> + <class>Initialize_OAI_UE</class> + <desc>Initialize NR UE USRP</desc> + <Initialize_OAI_UE_args>-C 3510000000 --numerology 1 -r 106 --phy-test --usrp-args "addr=192.168.30.2,clock_source=external,time_source=external" --threadoffset 16</Initialize_OAI_UE_args> + <air_interface>NR</air_interface> + </testCase> + + <testCase id="090108"> + <class>Terminate_OAI_UE</class> + <desc>Terminate NR UE</desc> + <air_interface>NR</air_interface> + </testCase> + + <testCase id="090109"> + <class>Terminate_eNB</class> + <desc>Terminate gNB</desc> + <air_interface>NR</air_interface> + </testCase> + +</testCaseList> diff --git a/ci-scripts/xml_files/gnb_usrp_build.xml b/ci-scripts/xml_files/gnb_usrp_build.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b57c077bad00e3ffa4c33d1a007ce17cb3cce9f --- /dev/null +++ b/ci-scripts/xml_files/gnb_usrp_build.xml @@ -0,0 +1,39 @@ +<!-- + + Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The OpenAirInterface Software Alliance licenses this file to You under + the OAI Public License, Version 1.1 (the "License"); you may not use this file + except in compliance with the License. + You may obtain a copy of the License at + + http://www.openairinterface.org/?page_id=698 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For more information about the OpenAirInterface (OAI) Software Alliance: + contact@openairinterface.org + +--> +<testCaseList> + <htmlTabRef>gnb-build-tab</htmlTabRef> + <htmlTabName>Build-gNB</htmlTabName> + <htmlTabIcon>wrench</htmlTabIcon> + <TestCaseRequestedList> +010101 + </TestCaseRequestedList> + <TestCaseExclusionList></TestCaseExclusionList> + + <testCase id="010101"> + <mode>TesteNB</mode> + <class>Build_eNB</class> + <desc>Build gNB (USRP)</desc> + <Build_eNB_args>--gNB -w USRP</Build_eNB_args> + </testCase> + +</testCaseList> diff --git a/ci-scripts/xml_files/nr_ue_usrp_build.xml b/ci-scripts/xml_files/nr_ue_usrp_build.xml new file mode 100644 index 0000000000000000000000000000000000000000..7d8d97d2c5276e6b7b3feac3df842c627e1b03f6 --- /dev/null +++ b/ci-scripts/xml_files/nr_ue_usrp_build.xml @@ -0,0 +1,40 @@ +<!-- + + Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The OpenAirInterface Software Alliance licenses this file to You under + the OAI Public License, Version 1.1 (the "License"); you may not use this file + except in compliance with the License. + You may obtain a copy of the License at + + http://www.openairinterface.org/?page_id=698 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + For more information about the OpenAirInterface (OAI) Software Alliance: + contact@openairinterface.org + +--> +<testCaseList> + <htmlTabRef>nr-ue-build-tab</htmlTabRef> + <htmlTabName>Build-NR-UE</htmlTabName> + <htmlTabIcon>wrench</htmlTabIcon> + <TestCaseRequestedList> +010102 + </TestCaseRequestedList> + <TestCaseExclusionList></TestCaseExclusionList> + + <testCase id="010102"> + <mode>TestUE</mode> + <class>Build_OAI_UE</class> + <desc>Build NR UE (USRP)</desc> + <Build_OAI_UE_args>--nrUE -w USRP</Build_OAI_UE_args> + <clean_repository>false</clean_repository> + </testCase> + +</testCaseList> diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index 075c92ef25c6232ef62898f2ad93b44907f80301..de3f75eb5ec7dcdd3f8cabd587a49f1fdde5543a 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -812,6 +812,7 @@ include_directories("${OPENAIR_BIN_DIR}") # Legacy exact order +include_directories("${OPENAIR_DIR}/executables") include_directories("${OPENAIR2_DIR}/COMMON") include_directories("${OPENAIR2_DIR}/UTIL") include_directories("${OPENAIR2_DIR}/UTIL/LOG") @@ -2243,11 +2244,18 @@ if (${XFORMS}) ${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_scope.c ) set(XFORMS_SOURCE_SOFTMODEM - ${OPENAIR_TARGETS}/RT/USER/stats.c + ${OPENAIR_DIR}/targets/RT/USER/stats.c ) set(XFORMS_LIBRARIES "forms") endif (${XFORMS}) +include_directories ("/usr/include/X11") + +add_library(gnbScope MODULE + ${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_scope.c + ) +target_link_libraries(gnbScope forms) + set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}") #include T directory even if the T is off because T macros are in the code @@ -2291,6 +2299,24 @@ add_definitions(-DASN1_MINIMUM_VERSION=924) ################################# # add executables for operation ################################# +add_library(minimal_lib + ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/LOG/log.c + ${OPENAIR_DIR}/common/config/config_userapi.c + ${OPENAIR_DIR}/common/config/config_load_configmodule.c + ${OPENAIR_DIR}/common/config/config_cmdline.c + ${OPENAIR_DIR}/common/utils/minimal_stub.c + ) +target_link_libraries(minimal_lib pthread dl) + +add_executable(replay_node + ${OPENAIR_TARGETS}/ARCH/rfsimulator/stored_node.c + ) +target_link_libraries (replay_node minimal_lib) + +add_executable(measurement_display + ${OPENAIR_DIR}/common/utils/threadPool/measurement_display.c) +target_link_libraries (measurement_display minimal_lib) # lte-softmodem is both eNB and UE implementation ################################################### @@ -2497,19 +2523,16 @@ add_executable(nr-softmodem ${nr_rrc_h} ${s1ap_h} # ${OPENAIR_BIN_DIR}/messages_xml.h - ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_TARGETS}/RT/USER/nr-gnb.c - ${OPENAIR_TARGETS}/RT/USER/nr-ru.c - ${OPENAIR_TARGETS}/RT/USER/nr-softmodem.c + ${OPENAIR_DIR}/executables/nr-gnb.c + ${OPENAIR_DIR}/executables/nr-ru.c + ${OPENAIR_DIR}/executables/nr-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c - ${OPENAIR_TARGETS}/COMMON/create_nr_tasks.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} - ${XFORMS_SOURCE} - ${XFORMS_SOURCE_SOFTMODEM} + ${XFORMS_SOURCE_NR} ${T_SOURCE} ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} @@ -2535,13 +2558,10 @@ add_executable(nr-softmodem-nos1 ${rrc_h} ${s1ap_h} # ${OPENAIR_BIN_DIR}/messages_xml.h - ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c - ${OPENAIR_TARGETS}/RT/USER/nr-gnb.c - ${OPENAIR_TARGETS}/RT/USER/nr-ru.c - ${OPENAIR_TARGETS}/RT/USER/nr-softmodem.c + ${OPENAIR_DIR}/executables/nr-gnb.c + ${OPENAIR_DIR}/executables/nr-ru.c + ${OPENAIR_DIR}/executables/nr-softmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c - ${OPENAIR_TARGETS}/COMMON/create_tasks.c - ${OPENAIR_TARGETS}/COMMON/create_nr_tasks.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c @@ -2549,8 +2569,7 @@ add_executable(nr-softmodem-nos1 ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${GTPU_need_ITTI} - ${XFORMS_SOURCE} - ${XFORMS_SOURCE_SOFTMODEM} + ${XFORMS_SOURCE_NR} ${T_SOURCE} ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} @@ -2586,7 +2605,6 @@ add_executable(nr-uesoftmodem ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${XFORMS_SOURCE_NR} - ${XFORMS_SOURCE_SOFTMODEM} ${T_SOURCE} ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} @@ -2610,17 +2628,14 @@ add_executable(nr-uesoftmodem-nos1 ${rrc_h} ${s1ap_h} # ${OPENAIR_BIN_DIR}/messages_xml.h - ${OPENAIR_TARGETS}/RT/USER/rt_wrapper.c ${OPENAIR_DIR}/executables/nr-ue.c ${OPENAIR_DIR}/executables/nr-uesoftmodem.c ${OPENAIR1_DIR}/SIMULATION/TOOLS/taus.c - #${OPENAIR_TARGETS}/COMMON/create_tasks_ue.c ${OPENAIR_TARGETS}/ARCH/COMMON/common_lib.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR_DIR}/common/utils/utils.c ${OPENAIR_DIR}/common/utils/system.c ${XFORMS_SOURCE_NR} - ${XFORMS_SOURCE_SOFTMODEM} ${T_SOURCE} ${CONFIG_SOURCES} ${SHLIB_LOADER_SOURCES} @@ -2673,6 +2688,7 @@ target_link_libraries (nr-uesoftmodem-nos1 ${T_LIB}) add_executable(dlsim_tm4 ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/dlsim_tm4.c ${OPENAIR1_DIR}/PHY/TOOLS/lte_phy_scope_tm4.c + ${OPENAIR_DIR}/common/utils/system.c ${T_SOURCE} ) target_link_libraries (dlsim_tm4 @@ -2699,18 +2715,21 @@ target_link_libraries(ldpctest SIMU PHY PHY_NR m ${ATLAS_LIBRARIES}) add_executable(nr_dlschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/system.c ${T_SOURCE}) target_link_libraries(nr_dlschsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl) add_executable(nr_pbchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/system.c ${T_SOURCE}) target_link_libraries(nr_pbchsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl) add_executable(nr_dlsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/system.c ${T_SOURCE}) target_link_libraries(nr_dlsim -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON RRC_LIB NR_RRC_LIB CONFIG_LIB L2_NR -Wl,--end-group m pthread ${ATLAS_LIBRARIES} ${T_LIB} dl) @@ -2726,6 +2745,7 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr add_executable(${myExe} ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c ${OPENAIR_DIR}/common/utils/backtrace.c + ${OPENAIR_DIR}/common/utils/system.c ${XFORMS_SOURCE} ${T_SOURCE} ${CONFIG_SOURCES} diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index bdfc7e5a59375c0b59ea04837f8d9eca43cfd593..c95219b5142c99581bffc4cea89465e9a71ce96c 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -419,11 +419,6 @@ function main() { CMAKE_CMD="$CMAKE_CMD .." echo_info "CMAKE_CMD=$CMAKE_CMD" - if [ "$eNB" = "1" -o "$gNB" = "1" ] && [ "$UE" = "1" -o "$nrUE" = "1" ]; then - echo_error "Cannot build UE/nrUE and eNB/gNB on one build_oai execution" - echo_error "use 2 build_oai invocations" - exit - fi ######################################################### # check validity of HW and TP parameters for eNB / gNB diff --git a/common/utils/minimal_stub.c b/common/utils/minimal_stub.c new file mode 100644 index 0000000000000000000000000000000000000000..86454fe53f87dad750a11d7c0a1f07d67b5e5379 --- /dev/null +++ b/common/utils/minimal_stub.c @@ -0,0 +1,4 @@ +int T_stdout; + +void exit_function(const char *file, const char *function, const int line, const char *s) { +} diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 3d0bd0e1a34024673b8055351c21559ef5e44c2a..e8b12fcd4dee09953a7a7216541a6def4993a6a0 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -8,6 +8,7 @@ #include <intertask_interface.h> +#include <common/utils/system.h> typedef struct timer_elm_s { timer_type_t type; ///< Timer type @@ -263,7 +264,8 @@ extern "C" { pthread_mutex_unlock (&t->queue_cond_lock); } - void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) { + void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) + { //reception of one message, non-blocking task_list_t *t=&tasks[task_id]; pthread_mutex_lock(&t->queue_cond_lock); @@ -278,24 +280,13 @@ extern "C" { pthread_mutex_unlock (&t->queue_cond_lock); } - int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *args_p) { + int itti_create_task(task_id_t task_id, + void *(*start_routine)(void *), + void *args_p) + { task_list_t *t=&tasks[task_id]; - AssertFatal ( pthread_create (&t->thread, NULL, start_routine, args_p) ==0, - "Thread creation for task %d failed!\n", task_id); - pthread_setname_np( t->thread, itti_get_task_name(task_id) ); + threadCreate (&t->thread, start_routine, args_p, (char*)itti_get_task_name(task_id),-1,OAI_PRIORITY_RT); LOG_I(TMR,"Created Posix thread %s\n", itti_get_task_name(task_id) ); -#if 1 // BMC test RT prio - { - int policy; - struct sched_param sparam; - memset(&sparam, 0, sizeof(sparam)); - sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-10; - policy = SCHED_FIFO ; - if (pthread_setschedparam(t->thread, policy, &sparam) != 0) { - LOG_E(TMR,"task %s : Failed to set pthread priority\n", itti_get_task_name(task_id) ); - } - } -#endif return 0; } @@ -303,14 +294,19 @@ extern "C" { pthread_exit (NULL); } - void itti_terminate_tasks(task_id_t task_id) { + void itti_terminate_tasks(task_id_t task_id) + { // Sends Terminate signals to all tasks. itti_send_terminate_message (task_id); usleep(100*1000); // Allow the tasks to receive the message before going returning to main thread } - int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info, - const message_info_t *messages_info) { + int itti_init(task_id_t task_max, + thread_id_t thread_max, + MessagesIds messages_id_max, + const task_info_t *tasks_info, + const message_info_t *messages_info) + { AssertFatal(TASK_MAX<UINT16_MAX, "Max itti tasks"); for(int i=0; i<task_max; ++i) { @@ -335,7 +331,8 @@ extern "C" { int32_t instance, timer_type_t type, void *timer_arg, - long *timer_id) { + long *timer_id) + { task_list_t *t=&tasks[task_id]; do { @@ -369,7 +366,8 @@ extern "C" { return 0; } - int timer_remove(long timer_id) { + int timer_remove(long timer_id) + { task_id_t task_id=(task_id_t)(timer_id&0xffff); int ret; pthread_mutex_lock (&tasks[task_id].queue_cond_lock); diff --git a/common/utils/simple_executable.h b/common/utils/simple_executable.h new file mode 100644 index 0000000000000000000000000000000000000000..98b75012dff61df05c20328904779734f2609067 --- /dev/null +++ b/common/utils/simple_executable.h @@ -0,0 +1,37 @@ +#ifndef __SIMPLE_EXE_H__ +#define __SIMPLE_EXE_H__ +#ifndef __USE_GNU +#define __USE_GNU +#endif +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <stdio.h> +#include <pthread.h> +#include <sched.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <stdint.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <common/utils/assertions.h> +#include <common/utils/LOG/log.h> +#include "common_lib.h" + +#ifdef T + #undef T + #define T(...) +#endif + +#endif diff --git a/common/utils/system.c b/common/utils/system.c index dcec681e2dcf2596b78352560672439e7bba58ee..31c1035129998da9a8340b1b80895e0dd4d44120 100644 --- a/common/utils/system.c +++ b/common/utils/system.c @@ -28,13 +28,23 @@ * separate process solves this problem. */ +#define _GNU_SOURCE #include "system.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> - +#include <stdint.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include <common/utils/assertions.h> +#include <common/utils/LOG/log.h> #define MAX_COMMAND 4096 static int command_pipe_read; @@ -50,37 +60,37 @@ static int module_initialized = 0; /* util functions */ /********************************************************************/ -static void lock_system(void) -{ +static void lock_system(void) { if (pthread_mutex_lock(&lock) != 0) { printf("pthread_mutex_lock fails\n"); abort(); } } -static void unlock_system(void) -{ +static void unlock_system(void) { if (pthread_mutex_unlock(&lock) != 0) { printf("pthread_mutex_unlock fails\n"); abort(); } } -static void write_pipe(int p, char *b, int size) -{ +static void write_pipe(int p, char *b, int size) { while (size) { int ret = write(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } } -static void read_pipe(int p, char *b, int size) -{ +static void read_pipe(int p, char *b, int size) { while (size) { int ret = read(p, b, size); + if (ret <= 0) exit(0); + b += ret; size -= ret; } @@ -95,14 +105,13 @@ static void read_pipe(int p, char *b, int size) * when the main process exits, because then a "read" on the pipe * will return 0, in which case "read_pipe" exits. */ -static void background_system_process(void) -{ +static void background_system_process(void) { int len; int ret; char command[MAX_COMMAND+1]; while (1) { - read_pipe(command_pipe_read, (char*)&len, sizeof(int)); + read_pipe(command_pipe_read, (char *)&len, sizeof(int)); read_pipe(command_pipe_read, command, len); ret = system(command); write_pipe(result_pipe_write, (char *)&ret, sizeof(int)); @@ -114,8 +123,7 @@ static void background_system_process(void) /* return -1 on error, 0 on success */ /********************************************************************/ -int background_system(char *command) -{ +int background_system(char *command) { int res; int len; @@ -125,18 +133,22 @@ int background_system(char *command) } len = strlen(command)+1; + if (len > MAX_COMMAND) { printf("FATAL: command too long. Increase MAX_COMMAND (%d).\n", MAX_COMMAND); printf("command was: '%s'\n", command); abort(); } + /* only one command can run at a time, so let's lock/unlock */ lock_system(); - write_pipe(command_pipe_write, (char*)&len, sizeof(int)); + write_pipe(command_pipe_write, (char *)&len, sizeof(int)); write_pipe(command_pipe_write, command, len); - read_pipe(result_pipe_read, (char*)&res, sizeof(int)); + read_pipe(result_pipe_read, (char *)&res, sizeof(int)); unlock_system(); + if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) return -1; + return 0; } @@ -146,17 +158,16 @@ int background_system(char *command) /* to be called very early by the main processing */ /********************************************************************/ -void start_background_system(void) -{ +void start_background_system(void) { int p[2]; pid_t son; - module_initialized = 1; if (pipe(p) == -1) { perror("pipe"); exit(1); } + command_pipe_read = p[0]; command_pipe_write = p[1]; @@ -164,10 +175,11 @@ void start_background_system(void) perror("pipe"); exit(1); } + result_pipe_read = p[0]; result_pipe_write = p[1]; - son = fork(); + if (son == -1) { perror("fork"); exit(1); @@ -181,6 +193,56 @@ void start_background_system(void) close(result_pipe_read); close(command_pipe_write); - background_system_process(); } + + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority){ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + struct sched_param sparam={0}; + sparam.sched_priority = priority; + pthread_attr_setschedparam(&attr, &sparam); + + pthread_create(t, &attr, func, param); + + pthread_setname_np(*t, name); + if (affinity != -1 ) { + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(affinity, &cpuset); + AssertFatal( pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset) == 0, "Error setting processor affinity"); + } + + pthread_attr_destroy(&attr); +} + +// Block CPU C-states deep sleep +void configure_linux(void) { + int ret; + static int latency_target_fd=-1; + uint32_t latency_target_value=10; // in microseconds + if (latency_target_fd == -1) { + if ( (latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR)) != -1 ) { + ret = write(latency_target_fd, &latency_target_value, sizeof(latency_target_value)); + if (ret == 0) { + printf("# error setting cpu_dma_latency to %d!: %s\n", latency_target_value, strerror(errno)); + close(latency_target_fd); + latency_target_fd=-1; + return; + } + } + } + if (latency_target_fd != -1) + LOG_I(HW,"# /dev/cpu_dma_latency set to %dus\n", latency_target_value); + else + LOG_E(HW,"Can't set /dev/cpu_dma_latency to %dus\n", latency_target_value); + + // Set CPU frequency to it's maximum + if ( 0 != system("for d in /sys/devices/system/cpu/cpu[0-9]*; do cat $d/cpufreq/cpuinfo_max_freq > $d/cpufreq/scaling_min_freq; done")) + LOG_W(HW,"Can't set cpu frequency\n"); + +} diff --git a/common/utils/system.h b/common/utils/system.h index 658c17adc1a476ce68c03d1510623c87c382ab29..a89a6c5b1729f0b968fbfd4baed9cfd3cce85b10 100644 --- a/common/utils/system.h +++ b/common/utils/system.h @@ -21,6 +21,12 @@ #ifndef _SYSTEM_H_OAI_ #define _SYSTEM_H_OAI_ +#include <stdint.h> +#include <pthread.h> +#ifdef __cplusplus +extern "C" { +#endif + /**************************************************** * send a command to the background process @@ -36,4 +42,23 @@ int background_system(char *command); void start_background_system(void); +void set_latency_target(void); +void configure_linux(void); + +void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name, int affinity, int priority); +#define OAI_PRIORITY_RT_LOW sched_get_priority_min(SCHED_FIFO) +#define OAI_PRIORITY_RT sched_get_priority_max(SCHED_FIFO)-10 +#define OAI_PRIORITY_RT_MAX sched_get_priority_max(SCHED_FIFO) + +void thread_top_init(char *thread_name, + int affinity, + uint64_t runtime, + uint64_t deadline, + uint64_t period); + +#ifdef __cplusplus +} +#endif + + #endif /* _SYSTEM_H_OAI_ */ diff --git a/common/utils/threadPool/Makefile b/common/utils/threadPool/Makefile index 6f0e884886839933ee173e63c02042dde1d6cb23..af0b44996cee1136afbe7babe430c2c9d44e78ba 100644 --- a/common/utils/threadPool/Makefile +++ b/common/utils/threadPool/Makefile @@ -1,8 +1,8 @@ all: measurement_display thread-pool-test measurement_display: measurement_display.c thread-pool.h - gcc measurement_display.c -I /data/openairinterface5g.nr/common/utils/ -I. /data/openairinterface5g.nr/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o measurement_display + gcc measurement_display.c -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. ${OPENAIR_DIR}/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o measurement_display thread-pool-test: thread-pool.c thread-pool.h - gcc -g thread-pool.c -I /data/openairinterface5g.nr/common/utils/ -I. /data/openairinterface5g.nr/common/utils/backtrace.c -lpthread -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o thread-pool-test + gcc -g thread-pool.c -I ${OPENAIR_DIR}/ -I ${OPENAIR_DIR}/common/utils/ -I. ${OPENAIR_DIR}/common/utils/backtrace.c -I ${OPENAIR_DIR}/openair2/COMMON ${OPENAIR_DIR}/common/utils/LOG/log.c ${OPENAIR_DIR}/common/config/config_userapi.c ${OPENAIR_DIR}/common/config/config_load_configmodule.c ${OPENAIR_DIR}/common/config/config_cmdline.c -lpthread -ldl -D TEST_THREAD_POOL -I../LOG -I../../utils/T -o thread-pool-test diff --git a/common/utils/threadPool/measurement_display.c b/common/utils/threadPool/measurement_display.c index ac7beca1fe00bac4b8d29d5906ded4cc5d7d1ea6..8f6e2c239a231c41a0f4c2f151dd3fcee468bf9b 100644 --- a/common/utils/threadPool/measurement_display.c +++ b/common/utils/threadPool/measurement_display.c @@ -2,22 +2,8 @@ Author: Laurent THOMAS, Open Cells copyleft: OpenAirInterface Software Alliance and it's licence */ +#include <common/utils/simple_executable.h> -#define __USE_GNU -#define _GNU_SOURCE -#include <stdio.h> -#include <pthread.h> -#include <sched.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/types.h> -#include <string.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <stdint.h> -#include <sys/stat.h> -#include <fcntl.h> #include "thread-pool.h" #define SEP "\t" @@ -26,7 +12,7 @@ uint64_t cpuCyclesMicroSec; int main(int argc, char *argv[]) { if(argc != 2) { - printf("Need one paramter: the trace Linux pipe (fifo)"); + printf("Need one parameter: the trace Linux pipe (fifo)"); exit(1); } diff --git a/common/utils/threadPool/thread-pool.c b/common/utils/threadPool/thread-pool.c index 4cc56fc9b8126f8a5f88d03ce8be780563b7d116..b45a8fa7227141ec611b90423a8ef651f00da9cd 100644 --- a/common/utils/threadPool/thread-pool.c +++ b/common/utils/threadPool/thread-pool.c @@ -49,23 +49,6 @@ void *one_thread(void *arg) { struct one_thread *myThread=(struct one_thread *) arg; struct thread_pool *tp=myThread->pool; - // configure the thread core assignment - // TBD: reserve the core for us exclusively - if ( myThread->coreID >= 0 && myThread->coreID < get_nprocs_conf()) { - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(myThread->coreID, &cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - } - - //Configure the thread scheduler policy for Linux - struct sched_param sparam= {0}; - sparam.sched_priority = sched_get_priority_max(SCHED_RR); - pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); - // set the thread name for debugging - sprintf(myThread->name,"Tpool_%d",myThread->coreID); - pthread_setname_np(pthread_self(), myThread->name ); - // Infinite loop to process requests do { notifiedFIFO_elt_t *elt=pullNotifiedFifoRemember(&tp->incomingFifo, myThread); @@ -106,10 +89,6 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { } else pool->traceFd=-1; - //Configure the thread scheduler policy for Linux - struct sched_param sparam= {0}; - sparam.sched_priority = sched_get_priority_max(SCHED_RR)-1; - pthread_setschedparam(pthread_self(), SCHED_RR, &sparam); pool->activated=true; initNotifiedFIFO(&pool->incomingFifo); char *saveptr, * curptr; @@ -136,7 +115,11 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { pool->allthreads->coreID=atoi(curptr); pool->allthreads->id=pool->nbThreads; pool->allthreads->pool=pool; - pthread_create(&pool->allthreads->threadID, NULL, one_thread, (void *)pool->allthreads); + //Configure the thread scheduler policy for Linux + // set the thread name for debugging + sprintf(pool->allthreads->name,"Tpool_%d",pool->allthreads->coreID); + threadCreate(&pool->allthreads->threadID, one_thread, (void *)pool->allthreads, + pool->allthreads->name, pool->allthreads->coreID, OAI_PRIORITY_RT); pool->nbThreads++; } @@ -151,6 +134,9 @@ void initTpool(char *params,tpool_t *pool, bool performanceMeas) { #ifdef TEST_THREAD_POOL +void exit_function(const char *file, const char *function, const int line, const char *s) { +} + struct testData { int id; char txt[30]; diff --git a/common/utils/threadPool/thread-pool.h b/common/utils/threadPool/thread-pool.h index aa0003fd8a3fec2ca009b5e484463edf7444647a..d6dc332c5ab6f9ebaabbe28d75171af01305a6d0 100644 --- a/common/utils/threadPool/thread-pool.h +++ b/common/utils/threadPool/thread-pool.h @@ -11,6 +11,7 @@ #include <sys/syscall.h> #include <assertions.h> #include <LOG/log.h> +#include <common/utils/system.h> #ifdef DEBUG #define THREADINIT PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP @@ -77,16 +78,18 @@ static inline void delNotifiedFIFO_elt(notifiedFIFO_elt_t *elt) { //LOG_W(UTIL,"delNotifiedFIFO on something not allocated by newNotifiedFIFO\n"); } +static inline void initNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) { + nf->inF=NULL; + nf->outF=NULL; +} static inline void initNotifiedFIFO(notifiedFIFO_t *nf) { mutexinit(nf->lockF); condinit (nf->notifF); - nf->inF=NULL; - nf->outF=NULL; + initNotifiedFIFO_nothreadSafe(nf); // No delete function: the creator has only to free the memory } -static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { - mutexlock(nf->lockF); +static inline void pushNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { msg->next=NULL; if (nf->outF == NULL) @@ -96,22 +99,39 @@ static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) nf->inF->next = msg; nf->inF = msg; - condbroadcast(nf->notifF); - mutexunlock(nf->lockF); } -static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) { +static inline void pushNotifiedFIFO(notifiedFIFO_t *nf, notifiedFIFO_elt_t *msg) { mutexlock(nf->lockF); + pushNotifiedFIFO_nothreadSafe(nf,msg); + condbroadcast(nf->notifF); + mutexunlock(nf->lockF); +} - while(nf->outF == NULL) - condwait(nf->notifF, nf->lockF); +static inline notifiedFIFO_elt_t *pullNotifiedFIFO_nothreadSafe(notifiedFIFO_t *nf) { + if (nf->outF == NULL) + return NULL; notifiedFIFO_elt_t *ret=nf->outF; + + if (nf->outF==nf->outF->next) + LOG_E(TMR,"Circular list in thread pool: push several times the same buffer is forbidden\n"); + nf->outF=nf->outF->next; if (nf->outF==NULL) nf->inF=NULL; + return ret; +} + +static inline notifiedFIFO_elt_t *pullNotifiedFIFO(notifiedFIFO_t *nf) { + mutexlock(nf->lockF); + notifiedFIFO_elt_t *ret; + + while((ret=pullNotifiedFIFO_nothreadSafe(nf)) == NULL) + condwait(nf->notifF, nf->lockF); + mutexunlock(nf->lockF); return ret; } @@ -122,18 +142,7 @@ static inline notifiedFIFO_elt_t *pollNotifiedFIFO(notifiedFIFO_t *nf) { if (tmp != 0 ) return NULL; - notifiedFIFO_elt_t *ret=nf->outF; - - if (ret!=NULL) { - if (nf->outF==nf->outF->next) - LOG_E(TMR,"Circular list in thread pool: push several times the same buffer is forbidden\n"); - - nf->outF=nf->outF->next; - } - - if (nf->outF==NULL) - nf->inF=NULL; - + notifiedFIFO_elt_t *ret=pullNotifiedFIFO_nothreadSafe(nf); mutexunlock(nf->lockF); return ret; } @@ -195,7 +204,7 @@ static inline notifiedFIFO_elt_t *pullTpool(notifiedFIFO_t *responseFifo, tpool_ if (t->measurePerf) msg->returnTime=rdtsc(); - if (t->traceFd) + if (t->traceFd >= 0) if(write(t->traceFd, msg, sizeof(*msg))); return msg; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c new file mode 100644 index 0000000000000000000000000000000000000000..c0571f2bc5e2eed5603d7555b3a94e195e91c9aa --- /dev/null +++ b/executables/nr-gnb.c @@ -0,0 +1,941 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file lte-enb.c + * \brief Top-level threads for gNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ + +#define _GNU_SOURCE +#include <pthread.h> + +#include "time_utils.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "assertions.h" +#include <common/utils/LOG/log.h> +#include <common/utils/system.h> + +#include "PHY/types.h" + +#include "PHY/INIT/phy_init.h" + +#include "PHY/defs_gNB.h" +#include "SCHED/sched_eNB.h" +#include "SCHED_NR/sched_nr.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/phy_extern.h" + + +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_extern.h" +#include "PHY_INTERFACE/phy_interface.h" +#include "common/utils/LOG/log_extern.h" +#include "UTIL/OTG/otg_tx.h" +#include "UTIL/OTG/otg_externs.h" +#include "UTIL/MATH/oml.h" +#include "common/utils/LOG/vcd_signal_dumper.h" +#include "UTIL/OPT/opt.h" +#include "enb_config.h" + + +#ifndef OPENAIR2 + #include "UTIL/OTG/otg_extern.h" +#endif + +#if defined(ENABLE_ITTI) + #if defined(ENABLE_USE_MME) + #include "s1ap_eNB.h" + #ifdef PDCP_USE_NETLINK + #include "SIMULATION/ETH_TRANSPORT/proto.h" + #endif + #endif +#endif + +#include "T.h" + +//#define DEBUG_THREADS 1 + +//#define USRP_DEBUG 1 +// Fix per CC openair rf/if device update +// extern openair0_device openair0; + + +#if defined(ENABLE_ITTI) + extern volatile int start_gNB; + extern volatile int start_UE; +#endif +extern volatile int oai_exit; + +extern openair0_config_t openair0_cfg[MAX_CARDS]; + +extern int transmission_mode; + +uint16_t sl_ahead=4; +uint16_t sf_ahead=4; +//pthread_t main_gNB_thread; + +time_stats_t softmodem_stats_mt; // main thread +time_stats_t softmodem_stats_hw; // hw acquisition +time_stats_t softmodem_stats_rxtx_sf; // total tx time +time_stats_t nfapi_meas; // total tx time +time_stats_t softmodem_stats_rx_sf; // total rx time + +/* mutex, cond and variable to serialize phy proc TX calls + * (this mechanism may be relaxed in the future for better + * performances) + */ +static struct { + pthread_mutex_t mutex_phy_proc_tx; + pthread_cond_t cond_phy_proc_tx; + volatile uint8_t phy_proc_CC_id; +} sync_phy_proc; + +extern double cpuf; + +void init_gNB(int,int); +void stop_gNB(int nb_inst); + +int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB); +int wakeup_tx(PHY_VARS_gNB *gNB); +extern PARALLEL_CONF_t get_thread_parallel_conf(void); +extern WORKER_CONF_t get_thread_worker_conf(void); + + +void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe); + +extern uint8_t nfapi_mode; +extern void oai_subframe_ind(uint16_t sfn, uint16_t sf); +extern void add_subframe(uint16_t *frameP, uint16_t *subframeP, int offset); + +//#define TICK_TO_US(ts) (ts.diff) +#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) + + +static inline int rxtx(PHY_VARS_gNB *gNB,gNB_L1_rxtx_proc_t *proc, char *thread_name) { + start_meas(&softmodem_stats_rxtx_sf); + + // ******************************************************************* + + if (nfapi_mode == 1) { + // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick + uint16_t frame = proc->frame_rx; + uint16_t slot = proc->slot_rx; + //add_subframe(&frame, &subframe, 4); + //oai_subframe_ind(proc->frame_tx, proc->subframe_tx); + //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe); + start_meas(&nfapi_meas); + oai_subframe_ind(frame, slot); + stop_meas(&nfapi_meas); + + if (gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus|| + gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs || + gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs || + gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles || + gNB->UL_INFO.cqi_ind.number_of_cqis + ) { + LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d \n", + NFAPI_SFNSF2DEC(gNB->UL_INFO.rx_ind.sfn_sf), gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus, + NFAPI_SFNSF2DEC(gNB->UL_INFO.harq_ind.sfn_sf), gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs, + NFAPI_SFNSF2DEC(gNB->UL_INFO.crc_ind.sfn_sf), gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs, + NFAPI_SFNSF2DEC(gNB->UL_INFO.rach_ind.sfn_sf), gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles, + gNB->UL_INFO.cqi_ind.number_of_cqis, + proc->frame_rx, proc->slot_rx, + proc->frame_tx, proc->slot_tx); + } + } + + /// NR disabling + // **************************************** + // Common RX procedures subframe n + T(T_GNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(proc->frame_tx), T_INT(proc->slot_tx)); + /* + // if this is IF5 or 3GPP_gNB + if (gNB && gNB->RU_list && gNB->RU_list[0] && gNB->RU_list[0]->function < NGFI_RAU_IF4p5) { + wakeup_prach_gNB(gNB,NULL,proc->frame_rx,proc->slot_rx); + } + + // UE-specific RX processing for subframe n + if (nfapi_mode == 0 || nfapi_mode == 1) { + phy_procedures_gNB_uespec_RX(gNB, proc, no_relay ); + } + */ + pthread_mutex_lock(&gNB->UL_INFO_mutex); + gNB->UL_INFO.frame = proc->frame_rx; + gNB->UL_INFO.slot = proc->slot_rx; + gNB->UL_INFO.module_id = gNB->Mod_id; + gNB->UL_INFO.CC_id = gNB->CC_id; + gNB->if_inst->NR_UL_indication(&gNB->UL_INFO); + pthread_mutex_unlock(&gNB->UL_INFO_mutex); + + /// end + // ***************************************** + // TX processing for subframe n+sl_ahead + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + //if (wait_CCs(proc)<0) return(-1); + + if (oai_exit) return(-1); + + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { + phy_procedures_gNB_TX(gNB, proc, 1); + } + + stop_meas( &softmodem_stats_rxtx_sf ); + LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->slot_rx, proc->frame_tx, proc->slot_tx); +#if 0 + LOG_D(PHY, "rxtx:%lld nfapi:%lld phy:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ", + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now, + TICK_TO_US(gNB->phy_proc), + TICK_TO_US(gNB->phy_proc_tx), + TICK_TO_US(gNB->phy_proc_rx), + TICK_TO_US(gNB->rx_prach), + TICK_TO_US(gNB->ofdm_mod_stats), + softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now); + LOG_D(PHY, + "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ", + TICK_TO_US(gNB->dlsch_encoding_stats), + TICK_TO_US(gNB->dlsch_modulation_stats), + TICK_TO_US(gNB->dlsch_scrambling_stats), + TICK_TO_US(gNB->dlsch_rate_matching_stats), + TICK_TO_US(gNB->dlsch_turbo_encoding_stats), + TICK_TO_US(gNB->dlsch_interleaving_stats), + TICK_TO_US(gNB->rx_dft_stats)); + LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ", + TICK_TO_US(gNB->ulsch_channel_estimation_stats), + TICK_TO_US(gNB->ulsch_freq_offset_estimation_stats), + TICK_TO_US(gNB->ulsch_decoding_stats), + TICK_TO_US(gNB->ulsch_demodulation_stats), + TICK_TO_US(gNB->ulsch_rate_unmatching_stats)); + LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ", + TICK_TO_US(gNB->ulsch_turbo_decoding_stats), + TICK_TO_US(gNB->ulsch_deinterleaving_stats), + TICK_TO_US(gNB->ulsch_demultiplexing_stats), + TICK_TO_US(gNB->ulsch_llr_stats), + TICK_TO_US(gNB->ulsch_tc_init_stats)); + LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n", + TICK_TO_US(gNB->ulsch_tc_alpha_stats), + TICK_TO_US(gNB->ulsch_tc_beta_stats), + TICK_TO_US(gNB->ulsch_tc_gamma_stats), + TICK_TO_US(gNB->ulsch_tc_ext_stats), + TICK_TO_US(gNB->ulsch_tc_intl1_stats), + TICK_TO_US(gNB->ulsch_tc_intl2_stats) + ); +#endif + return(0); +} + +static void *gNB_L1_thread_tx(void *param) { + PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param; + gNB_L1_proc_t *gNB_proc = &gNB->proc; + gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc_tx; + //PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; + char thread_name[100]; + sprintf(thread_name,"TXnp4_%d\n",&gNB->proc.L1_proc == proc ? 0 : 1); + + //wait_sync("tx_thread"); + + while (!oai_exit) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX1, 0 ); + + if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX1, 1 ); + + if (oai_exit) break; + + // ***************************************** + // TX processing for subframe n+4 + // run PHY TX procedures the one after the other for all CCs to avoid race conditions + // (may be relaxed in the future for performance reasons) + // ***************************************** + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX1_GNB,proc->slot_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX1_GNB,proc->slot_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX1_GNB,proc->frame_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX1_GNB,proc->frame_rx); + phy_procedures_gNB_TX(gNB, proc, 1); + pthread_mutex_lock( &proc->mutex ); + proc->instance_cnt = -1; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + } + + pthread_mutex_unlock( &proc->mutex ); + wakeup_txfh(proc,gNB); + } + + return 0; +} + +/*! + * \brief The RX UE-specific and TX thread of gNB. + * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ + +static void *gNB_L1_thread( void *param ) { + static int gNB_thread_rxtx_status; + PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param; + gNB_L1_proc_t *gNB_proc = &gNB->proc; + gNB_L1_rxtx_proc_t *proc = &gNB_proc->L1_proc; + //PHY_VARS_gNB *gNB = RC.gNB[0][proc->CC_id]; + char thread_name[100]; + // set default return value + gNB_thread_rxtx_status = 0; + sprintf(thread_name,"RXn_TXnp4_%d",&gNB->proc.L1_proc == proc ? 0 : 1); + + while (!oai_exit) { + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 0 ); + + if (wait_on_condition(&proc->mutex,&proc->cond,&proc->instance_cnt,thread_name)<0) break; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_PROC_RXTX0, 1 ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_TX0_GNB,proc->slot_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SLOT_NUMBER_RX0_GNB,proc->slot_rx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_GNB,proc->frame_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_GNB,proc->frame_rx); + + if (oai_exit) break; + + if (gNB->CC_id==0) { + if (rxtx(gNB,proc,thread_name) < 0) break; + } + + if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) { + phy_procedures_gNB_TX(gNB, proc, 1); + } + + if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break; + + if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { + wakeup_tx(gNB); + } else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) { + wakeup_txfh(proc,gNB); + } + } // while !oai_exit + + LOG_D(PHY, " *** Exiting gNB thread RXn_TXnp4\n"); + gNB_thread_rxtx_status = 0; + return &gNB_thread_rxtx_status; +} + + +#if 0 //defined(ENABLE_ITTI) && defined(ENABLE_USE_MME) +// Wait for gNB application initialization to be complete (gNB registration to MME) +static void wait_system_ready (char *message, volatile int *start_flag) { + static char *indicator[] = {". ", ".. ", "... ", ".... ", ".....", + " ....", " ...", " ..", " .", " " + }; + int i = 0; + + while ((!oai_exit) && (*start_flag == 0)) { + LOG_N(EMU, message, indicator[i]); + fflush(stdout); + i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0])); + usleep(200000); + } + + LOG_D(EMU,"\n"); +} +#endif + + + + + +void gNB_top(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, char *string, struct RU_t_s *ru) { + gNB_L1_proc_t *proc = &gNB->proc; + gNB_L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *ru_proc=&ru->proc; + proc->frame_rx = frame_rx; + proc->slot_rx = slot_rx; + + if (!oai_exit) { + T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->slot_rx)); + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->slot_rx = ru_proc->tti_rx; + L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; + + if (rxtx(gNB,L1_proc,string) < 0) LOG_E(PHY,"gNB %d CC_id %d failed during execution\n",gNB->Mod_id,gNB->CC_id); + + ru_proc->timestamp_tx = L1_proc->timestamp_tx; + ru_proc->tti_tx = L1_proc->slot_tx; + ru_proc->frame_tx = L1_proc->frame_tx; + } +} + +int wakeup_txfh(gNB_L1_rxtx_proc_t *proc,PHY_VARS_gNB *gNB) { + RU_t *ru; + RU_proc_t *ru_proc; + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + //printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~inside wakeup_txfh %d.%d IC_RU = %d\n", proc->frame_tx, proc->slot_tx, proc->instance_cnt_RUs); + + if(wait_on_condition(&proc->mutex_RUs,&proc->cond_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) { + LOG_E(PHY,"Frame %d, subframe %d: TX FH not ready\n", proc->frame_tx, proc->slot_tx); + return(-1); + } + + pthread_mutex_lock(&gNB->proc.mutex_RU_tx); + gNB->proc.RU_mask_tx = 0; + pthread_mutex_unlock(&gNB->proc.mutex_RU_tx); + + if (release_thread(&proc->mutex_RUs,&proc->instance_cnt_RUs,"wakeup_txfh")<0) return(-1); + + for(int i=0; i<gNB->num_RU; i++) { + ru = gNB->RU_list[i]; + ru_proc = &ru->proc; + + if (ru_proc->instance_cnt_gNBs == 0) { + LOG_E(PHY,"Frame %d, subframe %d: TX FH thread busy, dropping Frame %d, subframe %d\n", ru_proc->frame_tx, ru_proc->tti_tx, proc->frame_rx, proc->slot_rx); + return(-1); + } + + if (pthread_mutex_timedlock(&ru_proc->mutex_gNBs,&wait) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB TX1 thread %d (IC %d)\n", ru_proc->tti_rx&1,ru_proc->instance_cnt_gNBs ); + exit_fun( "error locking mutex_gNB" ); + return(-1); + } + + ru_proc->instance_cnt_gNBs = 0; + ru_proc->timestamp_tx = proc->timestamp_tx; + ru_proc->tti_tx = proc->slot_tx; + ru_proc->frame_tx = proc->frame_tx; + LOG_I(PHY,"Signaling tx_thread_fh for %d.%d\n",ru_proc->frame_tx,ru_proc->tti_tx); + + // the thread can now be woken up + if (pthread_cond_signal(&ru_proc->cond_gNBs) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &ru_proc->mutex_gNBs ); + } + + return(0); +} + +int wakeup_tx(PHY_VARS_gNB *gNB) { + gNB_L1_proc_t *proc=&gNB->proc; + gNB_L1_rxtx_proc_t *L1_proc_tx = &proc->L1_proc_tx; + gNB_L1_rxtx_proc_t *L1_proc = &proc->L1_proc; + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&L1_proc_tx->mutex,&wait) != 0) { + LOG_E(PHY, "[SCHED][eNB] ERROR locking mutex for eNB L1_thread_tx\n"); + exit_fun("ERROR pthread_lock"); + return(-1); + } + + while(L1_proc_tx->instance_cnt == 0) { + pthread_cond_wait(&L1_proc_tx->cond,&L1_proc_tx->mutex); + } + + L1_proc_tx->instance_cnt = 0; + L1_proc_tx->slot_rx = L1_proc->slot_rx; + L1_proc_tx->frame_rx = L1_proc->frame_rx; + L1_proc_tx->slot_tx = L1_proc->slot_tx; + L1_proc_tx->frame_tx = L1_proc->frame_tx; + L1_proc_tx->timestamp_tx = L1_proc->timestamp_tx; + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc_tx->cond) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &L1_proc_tx->mutex); + return(0); +} + +int wakeup_rxtx(PHY_VARS_gNB *gNB,RU_t *ru) { + gNB_L1_proc_t *proc=&gNB->proc; + gNB_L1_rxtx_proc_t *L1_proc=&proc->L1_proc; + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + RU_proc_t *ru_proc=&ru->proc; + int i; + struct timespec wait; + pthread_mutex_lock(&proc->mutex_RU); + + for (i=0; i<gNB->num_RU; i++) { + if (ru == gNB->RU_list[i]) { + if ((proc->RU_mask&(1<<i)) > 0) + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n", + gNB->Mod_id,proc->frame_rx,proc->slot_rx,ru->idx,gNB->num_RU,proc->RU_mask); + + proc->RU_mask |= (1<<i); + } + } + + if (proc->RU_mask != (1<<gNB->num_RU)-1) { // not all RUs have provided their information so return + LOG_E(PHY,"Not all RUs have provided their info\n"); + pthread_mutex_unlock(&proc->mutex_RU); + return(0); + } else { // all RUs have provided their information so continue on and wakeup gNB processing + proc->RU_mask = 0; + pthread_mutex_unlock(&proc->mutex_RU); + } + + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + /* accept some delay in processing - up to 5ms */ + for (i = 0; i < fp->slots_per_frame && L1_proc->instance_cnt == 0; i++) { + LOG_W( PHY,"[gNB] SFN.SL %d.%d, gNB RXn-TXnp4 thread busy!! (i %d, cnt %i)\n", L1_proc->frame_tx, L1_proc->slot_tx, i,L1_proc->instance_cnt); + usleep(100); + } + + if (L1_proc->instance_cnt == 0) { + exit_fun( "TX thread busy" ); + return(-1); + } + + // wake up TX for subframe n+sl_ahead + // lock the TX mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&L1_proc->mutex,&wait) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", L1_proc->slot_rx&1,L1_proc->instance_cnt ); + exit_fun( "error locking mutex" ); + return(-1); + } + + ++L1_proc->instance_cnt; + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+sl_ahead), so TS_tx = TX_rx+sl_ahead*samples_per_tti, + // and proc->slot_tx = proc->slot_rx+sl_ahead + L1_proc->timestamp_tx = ru_proc->timestamp_rx + (sl_ahead*fp->samples_per_slot); + L1_proc->frame_rx = ru_proc->frame_rx; + L1_proc->slot_rx = ru_proc->tti_rx; + L1_proc->frame_tx = (L1_proc->slot_rx > (fp->slots_per_frame-1-sl_ahead)) ? (L1_proc->frame_rx+1)&1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame; + LOG_I(PHY,"wakeupL1: passing parameter IC = %d, RX: %d.%d, TX: %d.%d to L1 sl_ahead = %d\n", L1_proc->instance_cnt, L1_proc->frame_rx, L1_proc->slot_rx, L1_proc->frame_tx, L1_proc->slot_tx, sl_ahead); + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB RXn-TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &L1_proc->mutex ); + return(0); +} +/* +void wakeup_prach_gNB(PHY_VARS_gNB *gNB,RU_t *ru,int frame,int subframe) { + + gNB_L1_proc_t *proc = &gNB->proc; + LTE_DL_FRAME_PARMS *fp=&gNB->frame_parms; + int i; + + if (ru!=NULL) { + pthread_mutex_lock(&proc->mutex_RU_PRACH); + for (i=0;i<gNB->num_RU;i++) { + if (ru == gNB->RU_list[i]) { + LOG_D(PHY,"frame %d, subframe %d: RU %d for gNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,gNB->Mod_id,proc->RU_mask_prach,gNB->num_RU); + if ((proc->RU_mask_prach&(1<<i)) > 0) + LOG_E(PHY,"gNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n", + gNB->Mod_id,frame,subframe,ru->idx,gNB->num_RU,proc->RU_mask_prach); + proc->RU_mask_prach |= (1<<i); + } + } + if (proc->RU_mask_prach != (1<<gNB->num_RU)-1) { // not all RUs have provided their information so return + pthread_mutex_unlock(&proc->mutex_RU_PRACH); + return; + } + else { // all RUs have provided their information so continue on and wakeup gNB processing + proc->RU_mask_prach = 0; + pthread_mutex_unlock(&proc->mutex_RU_PRACH); + } + } + + // check if we have to detect PRACH first + if (is_prach_subframe(fp,frame,subframe)>0) { + LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe); + if (proc->instance_cnt_prach == 0) { + LOG_W(PHY,"[gNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe); + return; + } + + // wake up thread for PRACH RX + if (pthread_mutex_lock(&proc->mutex_prach) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_mutex_lock for gNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach); + exit_fun( "error locking mutex_prach" ); + return; + } + + ++proc->instance_cnt_prach; + // set timing for prach thread + proc->frame_prach = frame; + proc->subframe_prach = subframe; + + // the thread can now be woken up + if (pthread_cond_signal(&proc->cond_prach) != 0) { + LOG_E( PHY, "[gNB] ERROR pthread_cond_signal for gNB PRACH thread %d\n", proc->thread_index); + exit_fun( "ERROR pthread_cond_signal" ); + return; + } + + pthread_mutex_unlock( &proc->mutex_prach ); + } + +}*/ + +/*! + * \brief The prach receive thread of gNB. + * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +/* +static void* gNB_thread_prach( void* param ) { + static int gNB_thread_prach_status; + + + PHY_VARS_gNB *gNB= (PHY_VARS_gNB *)param; + gNB_L1_proc_t *proc = &gNB->proc; + + // set default return value + gNB_thread_prach_status = 0; + + + + while (!oai_exit) { + + if (oai_exit) break; + + + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break; + + LOG_D(PHY,"Running gNB prach procedures\n"); + prach_procedures(gNB +#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,0 +#endif + ); + + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"gNB_prach_thread") < 0) break; + } + + LOG_I(PHY, "Exiting gNB thread PRACH\n"); + + gNB_thread_prach_status = 0; + return &gNB_thread_prach_status; +} +*/ + +extern void init_td_thread(PHY_VARS_gNB *); +extern void init_te_thread(PHY_VARS_gNB *); + +void init_gNB_proc(int inst) { + int i=0; + int CC_id; + PHY_VARS_gNB *gNB; + gNB_L1_proc_t *proc; + gNB_L1_rxtx_proc_t *L1_proc,*L1_proc_tx; + LOG_I(PHY,"%s(inst:%d) RC.nb_nr_CC[inst]:%d \n",__FUNCTION__,inst,RC.nb_nr_CC[inst]); + + for (CC_id=0; CC_id<RC.nb_nr_CC[inst]; CC_id++) { + gNB = RC.gNB[inst][CC_id]; +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing gNB processes instance:%d CC_id %d \n",inst,CC_id); +#endif + proc = &gNB->proc; + L1_proc = &proc->L1_proc; + L1_proc_tx = &proc->L1_proc_tx; + L1_proc->instance_cnt = -1; + L1_proc_tx->instance_cnt = -1; + L1_proc->instance_cnt_RUs = 0; + L1_proc_tx->instance_cnt_RUs = 0; + proc->instance_cnt_prach = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->CC_id = CC_id; + proc->first_rx =1; + proc->first_tx =1; + proc->RU_mask =0; + proc->RU_mask_tx = (1<<gNB->num_RU)-1; + proc->RU_mask_prach =0; + pthread_mutex_init( &gNB->UL_INFO_mutex, NULL); + pthread_mutex_init( &L1_proc->mutex, NULL); + pthread_mutex_init( &L1_proc_tx->mutex, NULL); + pthread_cond_init( &L1_proc->cond, NULL); + pthread_cond_init( &L1_proc_tx->cond, NULL); + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_RU,NULL); + pthread_mutex_init( &proc->mutex_RU_tx,NULL); + pthread_mutex_init( &proc->mutex_RU_PRACH,NULL); + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + LOG_I(PHY,"gNB->single_thread_flag:%d\n", gNB->single_thread_flag); + + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { + threadCreate( &L1_proc->pthread, gNB_L1_thread, gNB, "L1_proc", -1, OAI_PRIORITY_RT ); + threadCreate( &L1_proc_tx->pthread, gNB_L1_thread_tx, gNB,"L1_proc_tx", -1, OAI_PRIORITY_RT); + } + + //pthread_create( &proc->pthread_prach, attr_prach, gNB_thread_prach, gNB ); + char name[16]; + + if (gNB->single_thread_flag==0) { + snprintf( name, sizeof(name), "L1 %d", i ); + pthread_setname_np( L1_proc->pthread, name ); + snprintf( name, sizeof(name), "L1TX %d", i ); + pthread_setname_np( L1_proc_tx->pthread, name ); + } + + AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach); + } + + /* setup PHY proc TX sync mechanism */ + pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL); + pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL); + sync_phy_proc.phy_proc_CC_id = 0; +} + + + +/*! + * \brief Terminate gNB TX and RX threads. + */ +void kill_gNB_proc(int inst) { + int *status; + PHY_VARS_gNB *gNB; + gNB_L1_proc_t *proc; + gNB_L1_rxtx_proc_t *L1_proc, *L1_proc_tx; + + for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + gNB=RC.gNB[inst][CC_id]; + proc = &gNB->proc; + L1_proc = &proc->L1_proc; + L1_proc_tx = &proc->L1_proc_tx; + LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst ); + + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { + pthread_mutex_lock(&L1_proc->mutex); + L1_proc->instance_cnt = 0; + pthread_cond_signal(&L1_proc->cond); + pthread_mutex_unlock(&L1_proc->mutex); + pthread_mutex_lock(&L1_proc_tx->mutex); + L1_proc_tx->instance_cnt = 0; + pthread_cond_signal(&L1_proc_tx->cond); + pthread_mutex_unlock(&L1_proc_tx->mutex); + } + + proc->instance_cnt_prach = 0; + pthread_cond_signal( &proc->cond_prach ); + pthread_cond_signal( &proc->cond_asynch_rxtx ); + pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx); + // LOG_D(PHY, "joining pthread_prach\n"); + // pthread_join( proc->pthread_prach, (void**)&status ); + LOG_I(PHY, "Destroying prach mutex/cond\n"); + pthread_mutex_destroy( &proc->mutex_prach ); + pthread_cond_destroy( &proc->cond_prach ); + LOG_I(PHY, "Destroying UL_INFO mutex\n"); + pthread_mutex_destroy(&gNB->UL_INFO_mutex); + + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) { + LOG_I(PHY, "Joining L1_proc mutex/cond\n"); + pthread_join( L1_proc->pthread, (void **)&status ); + LOG_I(PHY, "Joining L1_proc_tx mutex/cond\n"); + pthread_join( L1_proc_tx->pthread, (void **)&status ); + } + + LOG_I(PHY, "Destroying L1_proc mutex/cond\n"); + pthread_mutex_destroy( &L1_proc->mutex ); + pthread_cond_destroy( &L1_proc->cond ); + LOG_I(PHY, "Destroying L1_proc_tx mutex/cond\n"); + pthread_mutex_destroy( &L1_proc_tx->mutex ); + pthread_cond_destroy( &L1_proc_tx->cond ); + pthread_mutex_destroy( &proc->mutex_RU ); + pthread_mutex_destroy( &proc->mutex_RU_tx ); + } +} + + + + +void reset_opp_meas(void) { + int sfn; + reset_meas(&softmodem_stats_mt); + reset_meas(&softmodem_stats_hw); + + for (sfn=0; sfn < 10; sfn++) { + reset_meas(&softmodem_stats_rxtx_sf); + reset_meas(&softmodem_stats_rx_sf); + } +} + + +void print_opp_meas(void) { + int sfn=0; + print_meas(&softmodem_stats_mt, "Main gNB Thread", NULL, NULL); + print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL); + + for (sfn=0; sfn < 10; sfn++) { + print_meas(&softmodem_stats_rxtx_sf,"[gNB][total_phy_proc_rxtx]",NULL, NULL); + print_meas(&softmodem_stats_rx_sf,"[gNB][total_phy_proc_rx]",NULL,NULL); + } +} + + +/// eNB kept in function name for nffapi calls, TO FIX +void init_eNB_afterRU(void) { + int inst,CC_id,ru_id,i,aa; + PHY_VARS_gNB *gNB; + LOG_I(PHY,"%s() RC.nb_nr_inst:%d\n", __FUNCTION__, RC.nb_nr_inst); + + for (inst=0; inst<RC.nb_nr_inst; inst++) { + LOG_I(PHY,"RC.nb_nr_CC[inst]:%d\n", RC.nb_nr_CC[inst]); + + for (CC_id=0; CC_id<RC.nb_nr_CC[inst]; CC_id++) { + LOG_I(PHY,"RC.nb_nr_CC[inst:%d][CC_id:%d]:%p\n", inst, CC_id, RC.gNB[inst][CC_id]); + gNB = RC.gNB[inst][CC_id]; + phy_init_nr_gNB(gNB,0,0); + + // map antennas and PRACH signals to gNB RX + if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id); + + LOG_I(PHY,"Mapping RX ports from %d RUs to gNB %d\n",gNB->num_RU,gNB->Mod_id); + //LOG_I(PHY,"Overwriting gNB->prach_vars.rxsigF[0]:%p\n", gNB->prach_vars.rxsigF[0]); + gNB->prach_vars.rxsigF[0] = (int16_t **)malloc16(64*sizeof(int16_t *)); + LOG_I(PHY,"gNB->num_RU:%d\n", gNB->num_RU); + + for (ru_id=0,aa=0; ru_id<gNB->num_RU; ru_id++) { + AssertFatal(gNB->RU_list[ru_id]->common.rxdataF!=NULL, + "RU %d : common.rxdataF is NULL\n", + gNB->RU_list[ru_id]->idx); + AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF!=NULL, + "RU %d : prach_rxsigF is NULL\n", + gNB->RU_list[ru_id]->idx); + + for (i=0; i<gNB->RU_list[ru_id]->nb_rx; aa++,i++) { + LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa); + gNB->prach_vars.rxsigF[0][aa] = gNB->RU_list[ru_id]->prach_rxsigF[i]; + gNB->common_vars.rxdataF[aa] = gNB->RU_list[ru_id]->common.rxdataF[i]; + } + } + + /* TODO: review this code, there is something wrong. + * In monolithic mode, we come here with nb_antennas_rx == 0 + * (not tested in other modes). + */ + //init_precoding_weights(RC.gNB[inst][CC_id]); + } + + init_gNB_proc(inst); + } + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id); + RC.ru[ru_id]->nr_wakeup_rxtx = wakeup_rxtx; + // RC.ru[ru_id]->wakeup_prach_eNB = wakeup_prach_gNB; + RC.ru[ru_id]->gNB_top = gNB_top; + } +} + +void init_gNB(int single_thread_flag,int wait_for_sync) { + int CC_id; + int inst; + PHY_VARS_gNB *gNB; + LOG_I(PHY,"[nr-softmodem.c] gNB structure about to allocated RC.nb_nr_L1_inst:%d RC.nb_nr_L1_CC[0]:%d\n",RC.nb_nr_L1_inst,RC.nb_nr_L1_CC[0]); + + if (RC.gNB == NULL) RC.gNB = (PHY_VARS_gNB ***) malloc(RC.nb_nr_L1_inst*sizeof(PHY_VARS_gNB **)); + + LOG_I(PHY,"[lte-softmodem.c] gNB structure RC.gNB allocated\n"); + + for (inst=0; inst<RC.nb_nr_L1_inst; inst++) { + if (RC.gNB[inst] == NULL) RC.gNB[inst] = (PHY_VARS_gNB **) malloc(RC.nb_nr_CC[inst]*sizeof(PHY_VARS_gNB *)); + + for (CC_id=0; CC_id<RC.nb_nr_L1_CC[inst]; CC_id++) { + if (RC.gNB[inst][CC_id] == NULL) RC.gNB[inst][CC_id] = (PHY_VARS_gNB *) malloc(sizeof(PHY_VARS_gNB)); + + gNB = RC.gNB[inst][CC_id]; + gNB->abstraction_flag = 0; + gNB->single_thread_flag = single_thread_flag; + /*nr_polar_init(&gNB->nrPolar_params, + NR_POLAR_PBCH_MESSAGE_TYPE, + NR_POLAR_PBCH_PAYLOAD_BITS, + NR_POLAR_PBCH_AGGREGATION_LEVEL);*/ + LOG_I(PHY,"Initializing gNB %d CC_id %d single_thread_flag:%d\n",inst,CC_id,single_thread_flag); +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing gNB %d CC_id %d\n",inst,CC_id); +#endif + LOG_I(PHY,"Registering with MAC interface module\n"); + AssertFatal((gNB->if_inst = NR_IF_Module_init(inst))!=NULL,"Cannot register interface"); + gNB->if_inst->NR_Schedule_response = nr_schedule_response; + gNB->if_inst->NR_PHY_config_req = nr_phy_config_request; + memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO)); + memset((void *)&gNB->Sched_INFO,0,sizeof(gNB->Sched_INFO)); + LOG_I(PHY,"Setting indication lists\n"); + gNB->UL_INFO.rx_ind.rx_indication_body.rx_pdu_list = gNB->rx_pdu_list; + gNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = gNB->crc_pdu_list; + gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list; + gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list; + gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list; + gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list; + gNB->prach_energy_counter = 0; + } + } + + LOG_I(PHY,"[nr-softmodem.c] gNB structure allocated\n"); +} + + +void stop_gNB(int nb_inst) { + for (int inst=0; inst<nb_inst; inst++) { + LOG_I(PHY,"Killing gNB %d processing threads\n",inst); + kill_gNB_proc(inst); + } +} diff --git a/executables/nr-ru.c b/executables/nr-ru.c new file mode 100644 index 0000000000000000000000000000000000000000..e6e62ad5532ccf113f05ec21b788a345e53c2f47 --- /dev/null +++ b/executables/nr-ru.c @@ -0,0 +1,2280 @@ +/******************************************************************************* + OpenAirInterface + Copyright(c) 1999 - 2014 Eurecom + + OpenAirInterface is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenAirInterface is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OpenAirInterface.The full GNU General Public License is + included in this distribution in the file called "COPYING". If not, + see <http://www.gnu.org/licenses/>. + + Contact Information + OpenAirInterface Admin: openair_admin@eurecom.fr + OpenAirInterface Tech : openair_tech@eurecom.fr + OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr + + Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE + +*******************************************************************************/ + +/*! \file lte-enb.c + * \brief Top-level threads for eNodeB + * \author R. Knopp, F. Kaltenberger, Navid Nikaein + * \date 2012 + * \version 0.1 + * \company Eurecom + * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr + * \note + * \warning + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sched.h> +#include <linux/sched.h> +#include <signal.h> +#include <execinfo.h> +#include <getopt.h> +#include <sys/sysinfo.h> + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "common/utils/assertions.h" +#include "common/utils/system.h" +#include "msc.h" + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h" + +#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/LTE_TRANSPORT/if5_tools.h" + +#include "PHY/types.h" +#include "PHY/defs_nr_common.h" +#include "PHY/phy_extern.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" +#include "PHY/INIT/phy_init.h" +#include "SCHED/sched_eNB.h" +#include "SCHED_NR/sched_nr.h" + +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_extern.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_extern.h" +#include "PHY_INTERFACE/phy_interface.h" + +#include "common/utils/LOG/log.h" +#include "common/utils/LOG/vcd_signal_dumper.h" + +#include "enb_config.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif + +/* these variables have to be defined before including ENB_APP/enb_paramdef.h */ +static int DEFBANDS[] = {7}; +static int DEFENBS[] = {0}; + +#include "ENB_APP/enb_paramdef.h" +#include "common/config/config_userapi.h" + +#ifndef OPENAIR2 + #include "UTIL/OTG/otg_extern.h" +#endif + +#if defined(ENABLE_ITTI) + #if defined(ENABLE_USE_MME) + #include "s1ap_eNB.h" + #ifdef PDCP_USE_NETLINK + #include "SIMULATION/ETH_TRANSPORT/proto.h" + #endif + #endif +#endif + +#include "T.h" +#include "nfapi_interface.h" + +extern volatile int oai_exit; + + +extern void nr_phy_free_RU(RU_t *); +extern void nr_phy_config_request(NR_PHY_Config_t *gNB); + +extern PARALLEL_CONF_t get_thread_parallel_conf(void); +extern WORKER_CONF_t get_thread_worker_conf(void); + +void init_RU(char *); +void stop_RU(int nb_ru); +void do_ru_sync(RU_t *ru); + +void configure_ru(int idx, + void *arg); + +void configure_rru(int idx, + void *arg); + +int attach_rru(RU_t *ru); + +int connect_rau(RU_t *ru); + +extern uint16_t sl_ahead; + +extern int emulate_rf; +extern int numerology; + +/*************************************************************/ +/* Functions to attach and configure RRU */ + +extern void wait_gNBs(void); + +int attach_rru(RU_t *ru) { + ssize_t msg_len,len; + RRU_CONFIG_msg_t rru_config_msg; + int received_capabilities=0; + wait_gNBs(); + + // Wait for capabilities + while (received_capabilities==0) { + memset((void *)&rru_config_msg,0,sizeof(rru_config_msg)); + rru_config_msg.type = RAU_tick; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d cannot access remote radio\n",ru->idx); + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + + // wait for answer with timeout + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RRU %d\n",ru->idx); + } else if (rru_config_msg.type == RRU_capabilities) { + AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len); + LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx, + (int)rru_config_msg.len,(int)msg_len, + ((RRU_capabilities_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0], + ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_rxgain[0], + ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_tx[0], + ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_rx[0]); + received_capabilities=1; + } else { + LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx); + } + } + + configure_ru(ru->idx, + (RRU_capabilities_t *)&rru_config_msg.msg[0]); + rru_config_msg.type = RRU_config; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx, + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send configuration to remote radio\n",ru->idx); + return 0; +} + +int connect_rau(RU_t *ru) { + RRU_CONFIG_msg_t rru_config_msg; + ssize_t msg_len; + int tick_received = 0; + int configuration_received = 0; + RRU_capabilities_t *cap; + int i; + int len; + + // wait for RAU_tick + while (tick_received == 0) { + msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + msg_len))<0) { + LOG_I(PHY,"Waiting for RAU\n"); + } else { + if (rru_config_msg.type == RAU_tick) { + LOG_I(PHY,"Tick received from RAU\n"); + tick_received = 1; + } else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type); + } + } + + // send capabilities + rru_config_msg.type = RRU_capabilities; + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); + cap = (RRU_capabilities_t *)&rru_config_msg.msg[0]; + LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", + (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx); + + switch (ru->function) { + case NGFI_RRU_IF4p5: + cap->FH_fmt = OAI_IF4p5_only; + break; + + case NGFI_RRU_IF5: + cap->FH_fmt = OAI_IF5_only; + break; + + case MBP_RRU_IF5: + cap->FH_fmt = MBP_IF5; + break; + + default: + AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function); + break; + } + + cap->num_bands = ru->num_bands; + + for (i=0; i<ru->num_bands; i++) { + LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n", + ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain); + cap->band_list[i] = ru->band[i]; + cap->nb_rx[i] = ru->nb_rx; + cap->nb_tx[i] = ru->nb_tx; + cap->max_pdschReferenceSignalPower[i] = ru->max_pdschReferenceSignalPower; + cap->max_rxgain[i] = ru->max_rxgain; + } + + AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), + "RU %d failed send capabilities to RAU\n",ru->idx); + // wait for configuration + rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + + while (configuration_received == 0) { + if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, + &rru_config_msg, + rru_config_msg.len))<0) { + LOG_I(PHY,"Waiting for configuration from RAU\n"); + } else { + LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, + ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], + ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + configure_rru(ru->idx, + (void *)&rru_config_msg.msg[0]); + configuration_received = 1; + } + } + + return 0; +} +/*************************************************************/ +/* Southbound Fronthaul functions, RCC/RAU */ + +// southbound IF5 fronthaul for 16-bit OAI format +static inline void fh_if5_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + + send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_RRH_GW_DL); +} + +// southbound IF5 fronthaul for Mobipass packet format +static inline void fh_if5_mobipass_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + + send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_MOBIPASS); +} + +// southbound IF4p5 fronthaul +static inline void fh_if4p5_south_out(RU_t *ru) { + if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + + LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx); + + if (nr_slot_select(&ru->gNB_list[0]->gNB_config,ru->proc.tti_tx)!=SF_UL) + send_IF4p5(ru,ru->proc.frame_tx, ru->proc.tti_tx, IF4p5_PDLFFT); +} + +/*************************************************************/ +/* Input Fronthaul from south RCC/RAU */ + +// Synchronous if5 from south +void fh_if5_south_in(RU_t *ru,int *frame, int *tti) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + recv_IF5(ru, &proc->timestamp_rx, *tti, IF5_RRH_GW_UL); + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*20))&1023; + proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%20; + + if (proc->first_rx == 0) { + if (proc->tti_rx != *tti) { + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*tti); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *tti = proc->tti_rx; + } + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); +} + +// Synchronous if4p5 from south +void fh_if4p5_south_in(RU_t *ru,int *frame,int *slot) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + int f,sl; + uint16_t packet_type; + uint32_t symbol_number=0; + uint32_t symbol_mask_full=0; + + /* + if ((fp->frame_type == TDD) && (subframe_select(fp,*slot)==SF_S)) + symbol_mask_full = (1<<fp->ul_symbols_in_S_subframe)-1; + else + symbol_mask_full = (1<<fp->symbols_per_slot)-1; + + AssertFatal(proc->symbol_mask[*slot]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*slot,proc->symbol_mask[*slot]);*/ + do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! + recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number); + + if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<<symbol_number); + else if (packet_type == IF4p5_PULTICK) { + if ((proc->first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame); + + if ((proc->first_rx==0) && (sl!=*slot)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sl,*slot,proc->first_rx); + + break; + } else if (packet_type == IF4p5_PRACH) { + // nothing in RU for RAU + } + + LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*slot,proc->symbol_mask[sl]); + } while(proc->symbol_mask[sl] != symbol_mask_full); + + //caculate timestamp_rx, timestamp_tx based on frame and subframe + proc->tti_rx = sl; + proc->frame_rx = f; + proc->timestamp_rx = ((proc->frame_rx * fp->slots_per_frame) + proc->tti_rx ) * fp->samples_per_slot ; + // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); + proc->tti_tx = (sl+sl_ahead)%fp->slots_per_frame; + proc->frame_tx = (sl>(fp->slots_per_frame-sl_ahead)) ? (f+1)&1023 : f; + + if (proc->first_rx == 0) { + if (proc->tti_rx != *slot) { + LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*slot); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *slot = proc->tti_rx; + } + + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, sl); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx ); + } + + proc->symbol_mask[proc->tti_rx] = 0; + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx); +} + +// asynchronous inbound if4p5 fronthaul from south +void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + uint16_t packet_type; + uint32_t symbol_number,symbol_mask,prach_rx; + // uint32_t got_prach_info=0; + symbol_number = 0; + symbol_mask = (1<<(fp->symbols_per_slot))-1; + prach_rx = 0; + + do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! + recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number); + + // grab first prach information for this new subframe + /*if (got_prach_info==0) { + prach_rx = is_prach_subframe(fp, proc->frame_rx, proc->tti_rx); + got_prach_info = 1; + }*/ + if (proc->first_rx != 0) { + *frame = proc->frame_rx; + *slot = proc->tti_rx; + proc->first_rx = 0; + } else { + if (proc->frame_rx != *frame) { + LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame); + exit_fun("Exiting"); + } + + if (proc->tti_rx != *slot) { + LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot); + exit_fun("Exiting"); + } + } + + if (packet_type == IF4p5_PULFFT) symbol_mask &= (~(1<<symbol_number)); + else if (packet_type == IF4p5_PRACH) prach_rx &= (~0x1); + } while( (symbol_mask > 0) || (prach_rx >0)); // haven't received all PUSCH symbols and PRACH information +} + + + + + +/*************************************************************/ +/* Input Fronthaul from North RRU */ + +// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output +// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates +void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) { + uint32_t symbol_number=0; + uint32_t symbol_mask, symbol_mask_full; + uint16_t packet_type; + /// **** incoming IF4p5 from remote RCC/RAU **** /// + symbol_number = 0; + symbol_mask = 0; + symbol_mask_full = (1<<(ru->nr_frame_parms->symbols_per_slot))-1; + + do { + recv_IF4p5(ru, frame, slot, &packet_type, &symbol_number); + symbol_mask = symbol_mask | (1<<symbol_number); + } while (symbol_mask != symbol_mask_full); + + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, *frame ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, *slot ); + } +} + +void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *slot) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + int tti_tx,frame_tx; + openair0_timestamp timestamp_tx; + recv_IF5(ru, ×tamp_tx, *slot, IF5_RRH_GW_DL); + // printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx); + tti_tx = (timestamp_tx/fp->samples_per_slot)%fp->slots_per_frame; + frame_tx = (timestamp_tx/(fp->samples_per_slot*fp->slots_per_frame))&1023; + + if (proc->first_tx != 0) { + *slot = tti_tx; + *frame = frame_tx; + proc->first_tx = 0; + } else { + AssertFatal(tti_tx == *slot, + "tti_tx %d is not what we expect %d\n",tti_tx,*slot); + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); + } +} + +void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config; + RU_proc_t *proc = &ru->proc; + uint16_t packet_type; + uint32_t symbol_number,symbol_mask,symbol_mask_full=0; + int slot_tx,frame_tx; + LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); + symbol_number = 0; + symbol_mask = 0; + + // symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_slot))-1; + do { + recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number); + + if ((nr_slot_select(cfg,slot_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); + + LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n", + *slot,nr_slot_select(cfg,*slot),frame_tx,slot_tx,symbol_number); + + if (proc->first_tx != 0) { + *frame = frame_tx; + *slot = slot_tx; + proc->first_tx = 0; + //symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_slot))-1; + } else { + AssertFatal(frame_tx == *frame, + "frame_tx %d is not what we expect %d\n",frame_tx,*frame); + AssertFatal(slot_tx == *slot, + "slot_tx %d is not what we expect %d\n",slot_tx,*slot); + } + + if (packet_type == IF4p5_PDLFFT) { + symbol_mask = symbol_mask | (1<<symbol_number); + } else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type); + } while (symbol_mask != symbol_mask_full); + + if (nr_slot_select(cfg,slot_tx) == SF_DL) stop_meas(&ru->rx_fhaul); + + proc->tti_tx = slot_tx; + proc->frame_tx = frame_tx; + + if ((frame_tx == 0)&&(slot_tx == 0)) proc->frame_tx_unwrap += 1024; + + proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->slots_per_frame) + (uint64_t)slot_tx) * (uint64_t)fp->samples_per_slot; + LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx); + + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot_tx ); + } + + if (ru->feptx_ofdm) ru->feptx_ofdm(ru); + + if (ru->fh_south_out) ru->fh_south_out(ru); +} + +void fh_if5_north_out(RU_t *ru) { + RU_proc_t *proc=&ru->proc; + uint8_t seqno=0; + /// **** send_IF5 of rxdata to BBU **** /// + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 ); + send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 ); +} + +// RRU IF4p5 northbound interface (RX) +void fh_if4p5_north_out(RU_t *ru) { + RU_proc_t *proc=&ru->proc; + + //NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + //const int subframe = proc->tti_rx; + if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx ); + + /* + if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { + /// **** in TDD during DL send_IF4 of ULTICK to RCC **** /// + send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULTICK); + return; + }*/ + start_meas(&ru->tx_fhaul); + send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT); + stop_meas(&ru->tx_fhaul); +} + +static void *emulatedRF_thread(void *param) { + RU_proc_t *proc = (RU_proc_t *) param; + int microsec = 500; // length of time to sleep, in miliseconds + struct timespec req = {0}; + req.tv_sec = 0; + req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2; + wait_sync("emulatedRF_thread"); + + while(!oai_exit) { + nanosleep(&req, (struct timespec *)NULL); + pthread_mutex_lock(&proc->mutex_emulateRF); + ++proc->instance_cnt_emulateRF; + pthread_mutex_unlock(&proc->mutex_emulateRF); + pthread_cond_signal(&proc->cond_emulateRF); + } + + return 0; +} + +void rx_rf(RU_t *ru,int *frame,int *slot) { + RU_proc_t *proc = &ru->proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + void *rxp[ru->nb_rx]; + unsigned int rxs; + int i; + openair0_timestamp ts,old_ts; + AssertFatal(*slot<fp->slots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); + + for (i=0; i<ru->nb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][*slot*fp->samples_per_slot]; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); + old_ts = proc->timestamp_rx; + LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",fp->samples_per_slot,*slot,rxp[0]); + + if(emulate_rf) { + wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); + release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); + rxs = fp->samples_per_slot; + ts = old_ts + rxs; + } else { + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &ts, + rxp, + fp->samples_per_slot, + ru->nb_rx); + } + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); + proc->timestamp_rx = ts-ru->ts_offset; + + //AssertFatal(rxs == fp->samples_per_subframe, + //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs); + if (rxs != fp->samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_slot,rxs); + + if (proc->first_rx == 1) { + ru->ts_offset = proc->timestamp_rx; + proc->timestamp_rx = 0; + } else { + if (proc->timestamp_rx - old_ts != fp->samples_per_slot) { + LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_slot,ru->ts_offset); + ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_slot); + proc->timestamp_rx = ts-ru->ts_offset; + } + } + + proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_slot*fp->slots_per_frame))&1023; + proc->tti_rx = (proc->timestamp_rx / fp->samples_per_slot)%fp->slots_per_frame; + // synchronize first reception to frame 0 subframe 0 + proc->timestamp_tx = proc->timestamp_rx+(sl_ahead*fp->samples_per_slot); + proc->tti_tx = (proc->tti_rx+sl_ahead)%fp->slots_per_frame; + proc->frame_tx = (proc->tti_rx>(fp->slots_per_frame-1-sl_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx; + LOG_I(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n", + ru->idx, + 0, + (unsigned long long int)proc->timestamp_rx, + (int)ru->ts_offset,proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame); + + // dump VCD output for first RU in list + if (ru == RC.ru[0]) { + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, proc->frame_rx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx ); + } + + if (proc->first_rx == 0) { + if (proc->tti_rx != *slot) { + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot); + exit_fun("Exiting"); + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame); + exit_fun("Exiting"); + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *slot = proc->tti_rx; + } + + //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); + + if (rxs != fp->samples_per_slot) { + //exit_fun( "problem receiving samples" ); + LOG_E(PHY, "problem receiving samples\n"); + } +} + + +void tx_rf(RU_t *ru) { + RU_proc_t *proc = &ru->proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + nfapi_nr_config_request_t *cfg = &ru->gNB_list[0]->gNB_config; + void *txp[ru->nb_tx]; + unsigned int txs; + int i; + T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(proc->frame_tx), T_INT(proc->tti_tx), + T_INT(0), T_BUFFER(&ru->common.txdata[0][proc->tti_tx * fp->samples_per_slot], fp->samples_per_slot * 4)); + nr_subframe_t SF_type = nr_slot_select(cfg,proc->tti_tx%fp->slots_per_frame); + int sf_extension = 0; + + if ((SF_type == SF_DL) || + (SF_type == SF_S)) { + int siglen=fp->samples_per_slot,flags=1; + /* + if (SF_type == SF_S) { + siglen = fp->dl_symbols_in_S_subframe*(fp->ofdm_symbol_size+fp->nb_prefix_samples0); + flags=3; // end of burst + } + if ((fp->frame_type == TDD) && + (SF_type == SF_DL)&& + (prevSF_type == SF_UL) && + (nextSF_type == SF_DL)) { + flags = 2; // start of burst + sf_extension = ru->N_TA_offset<<1; + } + + if ((cfg->subframe_config.duplex_mode == TDD) && + (SF_type == SF_DL)&& + (prevSF_type == SF_UL) && + (nextSF_type == SF_UL)) { + flags = 4; // start of burst and end of burst (only one DL SF between two UL) + sf_extension = ru->N_TA_offset<<1; + } */ + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx ); + + for (i=0; i<ru->nb_tx; i++) + txp[i] = (void *)&ru->common.txdata[i][(proc->tti_tx*fp->samples_per_slot)-sf_extension]; + + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-ru->openair0_cfg.tx_sample_advance)&0xffffffff ); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); + // prepare tx buffer pointers + txs = ru->rfdevice.trx_write_func(&ru->rfdevice, + proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension, + txp, + siglen+sf_extension, + ru->nb_tx, + flags); + LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx, + (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->tti_tx); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); + AssertFatal(txs == siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen); + } +} + + +/*! + * \brief The Asynchronous RX/TX FH thread of RAU/RCC/gNB/RRU. + * This handles the RX FH for an asynchronous RRU/UE + * \param param is a \ref gNB_L1_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void *ru_thread_asynch_rxtx( void *param ) { + static int ru_thread_asynch_rxtx_status; + RU_t *ru = (RU_t *)param; + RU_proc_t *proc = &ru->proc; + int subframe=0, frame=0; + // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe + wait_sync("ru_thread_asynch_rxtx"); + // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe + printf( "waiting for devices (ru_thread_asynch_rx)\n"); + wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch"); + printf( "devices ok (ru_thread_asynch_rx)\n"); + + while (!oai_exit) { + if (oai_exit) break; + + if (subframe==9) { + subframe=0; + frame++; + frame&=1023; + } else { + subframe++; + } + + LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n"); + + // asynchronous receive from south (Mobipass) + if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe); + // asynchronous receive from north (RRU IF4/IF5) + else if (ru->fh_north_asynch_in) { + if (nr_slot_select(&ru->gNB_list[0]->gNB_config,subframe)!=SF_UL) + ru->fh_north_asynch_in(ru,&frame,&subframe); + } else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n"); + } + + ru_thread_asynch_rxtx_status=0; + return(&ru_thread_asynch_rxtx_status); +} + + + + +/*! + * \brief The prach receive thread of RU. + * \param param is a \ref RU_proc_t structure which contains the info what to process. + * \returns a pointer to an int. The storage is not on the heap and must not be freed. + */ +static void *ru_thread_prach( void *param ) { + static int ru_thread_prach_status; + RU_t *ru = (RU_t *)param; + RU_proc_t *proc = (RU_proc_t *)&ru->proc; + // set default return value + ru_thread_prach_status = 0; + + while (RC.ru_mask>0) { + usleep(1e6); + LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__); + } + + LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__); + + while (!oai_exit) { + if (oai_exit) break; + + if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; + + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); + + /*if (ru->gNB_list[0]){ + prach_procedures( + ru->gNB_list[0] + #if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,0 + #endif + ); + } + else { + rx_prach(NULL, + ru, + NULL, + NULL, + NULL, + proc->frame_prach, + 0 + #if (RRC_VERSION >= MAKE_VERSION(14, 0, 0)) + ,0 + #endif + ); + } + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 ); */ + if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break; + } + + LOG_I(PHY, "Exiting RU thread PRACH\n"); + ru_thread_prach_status = 0; + return &ru_thread_prach_status; +} + + +int wakeup_synch(RU_t *ru) { + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + // wake up synch thread + // lock the synch mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU synch thread (IC %d)\n", ru->proc.instance_cnt_synch ); + exit_fun( "error locking mutex_synch" ); + return(-1); + } + + ++ru->proc.instance_cnt_synch; + + // the thread can now be woken up + if (pthread_cond_signal(&ru->proc.cond_synch) != 0) { + LOG_E( PHY, "[RU] ERROR pthread_cond_signal for RU synch thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + return(-1); + } + + pthread_mutex_unlock( &ru->proc.mutex_synch ); + return(0); +} + +void do_ru_synch(RU_t *ru) { + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + int i; + void *rxp[2],*rxp2[2]; + int32_t dummy_rx[ru->nb_rx][fp->samples_per_subframe] __attribute__((aligned(32))); + int rxs; + int ic; + + // initialize the synchronization buffer to the common_vars.rxdata + for (int i=0; i<ru->nb_rx; i++) + rxp[i] = &ru->common.rxdata[i][0]; + + double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0]; + double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0]; + + for (i=0; i<4; i++) { + ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i]; + ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1; + } + + ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0); + + while ((ru->in_synch ==0)&&(!oai_exit)) { + // read in frame + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp, + fp->samples_per_subframe*10, + ru->nb_rx); + + if (rxs != fp->samples_per_subframe*10) LOG_E(PHY,"requested %d samples, got %d\n",fp->samples_per_subframe*10,rxs); + + // wakeup synchronization processing thread + wakeup_synch(ru); + ic=0; + + while ((ic>=0)&&(!oai_exit)) { + // continuously read in frames, 1ms at a time, + // until we are done with the synchronization procedure + for (i=0; i<ru->nb_rx; i++) + rxp2[i] = (void *)&dummy_rx[i][0]; + + for (i=0; i<10; i++) + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp2, + fp->samples_per_subframe, + ru->nb_rx); + + pthread_mutex_lock(&ru->proc.mutex_synch); + ic = ru->proc.instance_cnt_synch; + pthread_mutex_unlock(&ru->proc.mutex_synch); + } // ic>=0 + } // in_synch==0 + + // read in rx_offset samples + LOG_I(PHY,"Resynchronizing by %d samples\n",ru->rx_offset); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, + &(proc->timestamp_rx), + rxp, + ru->rx_offset, + ru->nb_rx); + + for (i=0; i<4; i++) { + ru->rfdevice.openair0_cfg->rx_freq[i] = temp_freq1; + ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq2; + } + + ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0); +} + + + +void wakeup_gNB_L1s(RU_t *ru) { + int i; + PHY_VARS_gNB **gNB_list = ru->gNB_list; + LOG_D(PHY,"wakeup_gNB_L1s (num %d) for RU %d ru->gNB_top:%p\n",ru->num_gNB,ru->idx, ru->gNB_top); + + if (ru->num_gNB==1 && ru->gNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) { + // call gNB function directly + char string[20]; + sprintf(string,"Incoming RU %d",ru->idx); + LOG_D(PHY,"RU %d Call gNB_top\n",ru->idx); + ru->gNB_top(gNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string,ru); + } else { + LOG_D(PHY,"ru->num_gNB:%d\n", ru->num_gNB); + + for (i=0; i<ru->num_gNB; i++) { + LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->nr_wakeup_rxtx); + + if (ru->nr_wakeup_rxtx!=0 && ru->nr_wakeup_rxtx(gNB_list[i],ru) < 0) { + LOG_E(PHY,"could not wakeup gNB rxtx process for subframe %d\n", ru->proc.tti_rx); + } + } + } +} + +static inline int wakeup_prach_ru(RU_t *ru) { + struct timespec wait; + wait.tv_sec=0; + wait.tv_nsec=5000000L; + + if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) { + LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach); + exit_fun( "error locking mutex_rxtx" ); + return(-1); + } + + if (ru->proc.instance_cnt_prach==-1) { + ++ru->proc.instance_cnt_prach; + ru->proc.frame_prach = ru->proc.frame_rx; + ru->proc.subframe_prach = ru->proc.tti_rx; + + // DJP - think prach_procedures() is looking at gNB frame_prach + if (ru->gNB_list[0]) { + ru->gNB_list[0]->proc.frame_prach = ru->proc.frame_rx; + ru->gNB_list[0]->proc.slot_prach = ru->proc.tti_rx; + } + + LOG_I(PHY,"RU %d: waking up PRACH thread\n",ru->idx); + // the thread can now be woken up + AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n"); + } else LOG_W(PHY,"RU prach thread busy, skipping\n"); + + pthread_mutex_unlock( &ru->proc.mutex_prach ); + return(0); +} + +// this is for RU with local RF unit +void fill_rf_config(RU_t *ru, char *rf_config_file) { + int i; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config; //tmp index + openair0_config_t *cfg = &ru->openair0_cfg; + int N_RB = gNB_config->rf_config.dl_carrier_bandwidth.value; + int mu = gNB_config->subframe_config.numerology_index_mu.value; + + if (mu == NR_MU_0) { //or if LTE + if(N_RB == 100) { + if (fp->threequarter_fs) { + cfg->sample_rate=23.04e6; + cfg->samples_per_frame = 230400; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } else { + cfg->sample_rate=30.72e6; + cfg->samples_per_frame = 307200; + cfg->tx_bw = 10e6; + cfg->rx_bw = 10e6; + } + } else if(N_RB == 50) { + cfg->sample_rate=15.36e6; + cfg->samples_per_frame = 153600; + cfg->tx_bw = 5e6; + cfg->rx_bw = 5e6; + } else if (N_RB == 25) { + cfg->sample_rate=7.68e6; + cfg->samples_per_frame = 76800; + cfg->tx_bw = 2.5e6; + cfg->rx_bw = 2.5e6; + } else if (N_RB == 6) { + cfg->sample_rate=1.92e6; + cfg->samples_per_frame = 19200; + cfg->tx_bw = 1.5e6; + cfg->rx_bw = 1.5e6; + } else AssertFatal(1==0,"Unknown N_RB %d\n",N_RB); + } else if (mu == NR_MU_1) { + if(N_RB == 217) { + if (fp->threequarter_fs) { + cfg->sample_rate=92.16e6; + cfg->samples_per_frame = 921600; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; + } else { + cfg->sample_rate=122.88e6; + cfg->samples_per_frame = 1228800; + cfg->tx_bw = 40e6; + cfg->rx_bw = 40e6; + } + } else if(N_RB == 106) { + cfg->sample_rate=61.44e6; + cfg->samples_per_frame = 614400; + cfg->tx_bw = 20e6; + cfg->rx_bw = 20e6; + } else { + AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu); + } + } else { + AssertFatal(0 == 1,"Numerology %d not supported for the moment\n",mu); + } + + if (gNB_config->subframe_config.duplex_mode.value==TDD) + cfg->duplex_mode = duplex_mode_TDD; + else //FDD + cfg->duplex_mode = duplex_mode_FDD; + + cfg->Mod_id = 0; + cfg->num_rb_dl=N_RB; + cfg->tx_num_channels=ru->nb_tx; + cfg->rx_num_channels=ru->nb_rx; + + for (i=0; i<ru->nb_tx; i++) { + cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; + cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; + cfg->tx_gain[i] = ru->att_tx; + cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx; + cfg->configFilename = rf_config_file; + printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n", + i, cfg->tx_gain[i], + cfg->rx_gain[i], + cfg->tx_freq[i], + cfg->rx_freq[i]); + } +} + +/* this function maps the RU tx and rx buffers to the available rf chains. + Each rf chain is is addressed by the card number and the chain on the card. The + rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple + antennas are mapped to successive RF chains on the same card. */ +int setup_RU_buffers(RU_t *ru) { + int i,j; + int card,ant; + //uint16_t N_TA_offset = 0; + NR_DL_FRAME_PARMS *frame_parms; + //nfapi_nr_config_request_t *gNB_config = ru->gNB_list[0]->gNB_config; //tmp index + + if (ru) { + frame_parms = ru->nr_frame_parms; + printf("setup_RU_buffers: frame_parms = %p\n",frame_parms); + } else { + printf("RU[%d] not initialized\n", ru->idx); + return(-1); + } + + /* if (frame_parms->frame_type == TDD) { + if (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624; + else if (frame_parms->N_RB_DL == 50) ru->N_TA_offset = 624/2; + else if (frame_parms->N_RB_DL == 25) ru->N_TA_offset = 624/4; + } */ + if (ru->openair0_cfg.mmapped_dma == 1) { + // replace RX signal buffers with mmaped HW versions + for (i=0; i<ru->nb_rx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.rxdata[i]); + ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant]; + printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]); + + for (j=0; j<16; j++) { + printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]); + ru->common.rxdata[i][j] = 16-j; + } + } + + for (i=0; i<ru->nb_tx; i++) { + card = i/4; + ant = i%4; + printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant); + free(ru->common.txdata[i]); + ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant]; + printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]); + + for (j=0; j<16; j++) { + printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]); + ru->common.txdata[i][j] = 16-j; + } + } + } else { // not memory-mapped DMA + //nothing to do, everything already allocated in lte_init + } + + return(0); +} + +static void *ru_stats_thread(void *param) { + RU_t *ru = (RU_t *)param; + wait_sync("ru_stats_thread"); + + while (!oai_exit) { + sleep(1); + + if (opp_enabled == 1) { + if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL); + + if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL); + + if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); + + if (ru->fh_north_out) { + print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); + print_meas(&ru->compression,"compression",NULL,NULL); + print_meas(&ru->transport,"transport",NULL,NULL); + } + } + } + + return(NULL); +} + +static void *ru_thread_tx( void *param ) { + RU_t *ru = (RU_t *)param; + RU_proc_t *proc = &ru->proc; + PHY_VARS_gNB *gNB; + gNB_L1_proc_t *gNB_proc; + gNB_L1_rxtx_proc_t *L1_proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + char filename[40]; + int print_frame = 8; + int i = 0; + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + //CPU_SET(5, &cpuset); + //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + //wait_sync("ru_thread_tx"); + wait_on_condition(&proc->mutex_FH1,&proc->cond_FH1,&proc->instance_cnt_FH1,"ru_thread_tx"); + printf( "ru_thread_tx ready\n"); + + while (!oai_exit) { + if (oai_exit) break; + + LOG_I(PHY,"ru_thread_tx: Waiting for TX processing\n"); + // wait until eNBs are finished subframe RX n and TX n+4 + wait_on_condition(&proc->mutex_gNBs,&proc->cond_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx"); + + if (oai_exit) break; + + //printf("~~~~~~~~~~~~~~~~start process for ru_thread_tx %d.%d\n", proc->frame_tx, proc->tti_tx); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx ); + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx ); + + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + + if(!emulate_rf) { + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } else { + if(proc->frame_tx == print_frame) { + for (i=0; i<ru->nb_tx; i++) { + sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, proc->tti_tx); + LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); + + if(proc->tti_tx == 9) { + sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); + LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); + sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); + FILE *output_fd = fopen(filename,"w"); + + if (output_fd) { + fwrite(&ru->common.txdata[i][0], + sizeof(int32_t), + fp->samples_per_frame, + output_fd); + fclose(output_fd); + } else { + LOG_E(PHY,"Cannot write to file %s\n",filename); + } + }//if(proc->tti_tx == 9) + }//for (i=0; i<ru->nb_tx; i++) + }//if(proc->frame_tx == print_frame) + }//else emulate_rf + + release_thread(&proc->mutex_gNBs,&proc->instance_cnt_gNBs,"ru_thread_tx"); + + for(i = 0; i<ru->num_gNB; i++) { + gNB = ru->gNB_list[i]; + gNB_proc = &gNB->proc; + L1_proc = (get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)? &gNB_proc->L1_proc_tx : &gNB_proc->L1_proc; + pthread_mutex_lock(&gNB_proc->mutex_RU_tx); + + for (int j=0; j<gNB->num_RU; j++) { + if (ru == gNB->RU_list[j]) { + if ((gNB_proc->RU_mask_tx&(1<<j)) > 0) + LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n", + gNB->Mod_id,gNB_proc->frame_rx,gNB_proc->slot_rx,ru->idx,gNB->num_RU,gNB_proc->RU_mask_tx); + + gNB_proc->RU_mask_tx |= (1<<j); + } + } + + if (gNB_proc->RU_mask_tx != (1<<gNB->num_RU)-1) { // not all RUs have provided their information so return + pthread_mutex_unlock(&gNB_proc->mutex_RU_tx); + } else { // all RUs TX are finished so send the ready signal to eNB processing + gNB_proc->RU_mask_tx = 0; + pthread_mutex_unlock(&gNB_proc->mutex_RU_tx); + pthread_mutex_lock( &L1_proc->mutex_RUs); + L1_proc->instance_cnt_RUs = 0; + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond_RUs) != 0) { + LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n"); + exit_fun( "ERROR pthread_cond_signal" ); + } + + pthread_mutex_unlock( &L1_proc->mutex_RUs ); + } + } + } + + release_thread(&proc->mutex_FH1,&proc->instance_cnt_FH1,"ru_thread_tx"); + return 0; +} + +static void *ru_thread( void *param ) { + static int ru_thread_status; + RU_t *ru = (RU_t *)param; + RU_proc_t *proc = &ru->proc; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + int ret; + int slot = fp->slots_per_frame-1; + int frame =1023; + char filename[40],threadname[40]; + int print_frame = 8; + int i = 0; + // set default return value + ru_thread_status = 0; + // set default return value + sprintf(threadname,"ru_thread %d",ru->idx); + LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]); + + if(emulate_rf) { + fill_rf_config(ru,ru->rf_config_file); + nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, fp); + nr_dump_frame_parms(fp); + nr_phy_init_RU(ru); + + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + } else { + // Start IF device if any + if (ru->start_if) { + LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx); + AssertFatal(ru->start_if(ru,NULL) == 0, "Could not start the IF device\n"); + + if (ru->if_south == LOCAL_RF) ret = connect_rau(ru); + else ret = attach_rru(ru); + + AssertFatal(ret==0,"Cannot connect to remote radio\n"); + } + + if (ru->if_south == LOCAL_RF) { // configure RF parameters only + fill_rf_config(ru,ru->rf_config_file); + nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, fp); + nr_dump_frame_parms(fp); + nr_phy_init_RU(ru); + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + AssertFatal(ret==0,"Cannot connect to local radio\n"); + } + + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + } + } + + LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); + pthread_mutex_lock(&RC.ru_mutex); + RC.ru_mask &= ~(1<<ru->idx); + pthread_cond_signal(&RC.ru_cond); + pthread_mutex_unlock(&RC.ru_mutex); + wait_sync("ru_thread"); + + if(!emulate_rf) { + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + LOG_E(HW,"Could not start the RF device\n"); + else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); + } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + + // if an asnych_rxtx thread exists + // wakeup the thread because the devices are ready at this point + + if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) { + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx=0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + } else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx); + + // if this is a slave RRU, try to synchronize on the DL frequency + if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru); + } + + pthread_mutex_lock(&proc->mutex_FH1); + proc->instance_cnt_FH1 = 0; + pthread_mutex_unlock(&proc->mutex_FH1); + pthread_cond_signal(&proc->cond_FH1); + + // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices + while (!oai_exit) { + // these are local subframe/frame counters to check that we are in synch with the fronthaul timing. + // They are set on the first rx/tx in the underly FH routines. + if (slot==(fp->slots_per_frame-1)) { + slot=0; + frame++; + frame&=1023; + } else { + slot++; + } + + // synchronization on input FH interface, acquire signals/data and block + if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot); + else AssertFatal(1==0, "No fronthaul interface at south port"); + + LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0][0]:[RX:%d%d TX(SFN):%d]\n", + frame,slot, + proc->frame_rx,proc->tti_rx, + proc->frame_tx,proc->tti_tx, + RC.gNB[0][0]->proc.frame_rx,RC.gNB[0][0]->proc.slot_rx, + RC.gNB[0][0]->proc.frame_tx); + /* + LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n", + ru->do_prach, + is_prach_subframe(fp, proc->frame_rx, proc->tti_rx), + proc->frame_rx,proc->tti_rx); + + if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->tti_rx)==1)) { + wakeup_prach_ru(ru); + }*/ + + // adjust for timing offset between RU + //printf("~~~~~~~~~~~~~~~~~~~~~~~~~~%d.%d in ru_thread is in process\n", proc->frame_rx, proc->tti_rx); + if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023; + + // do RX front-end processing (frequency-shift, dft) if needed + if (ru->feprx) ru->feprx(ru); + + // At this point, all information for subframe has been received on FH interface + + // wakeup all gNB processes waiting for this RU + if (ru->num_gNB>0) wakeup_gNB_L1s(ru); + + if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD && ru->num_eNB==0) { + // do TX front-end processing if needed (precoding and/or IDFTs) + if (ru->feptx_prec) ru->feptx_prec(ru); + + // do OFDM if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru); + + if(!emulate_rf) { + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru); + + if (ru->fh_north_out) ru->fh_north_out(ru); + } else { + if(proc->frame_tx == print_frame) { + for (i=0; i<ru->nb_tx; i++) { + sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, proc->tti_tx); + LOG_M(filename,"txdataF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_slot_wCP, 1, 1); + + if(proc->tti_tx == 9) { + sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); + LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); + sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); + FILE *output_fd = fopen(filename,"w"); + + if (output_fd) { + fwrite(&ru->common.txdata[i][0], + sizeof(int32_t), + fp->samples_per_frame, + output_fd); + fclose(output_fd); + } else { + LOG_E(PHY,"Cannot write to file %s\n",filename); + } + }//if(proc->tti_tx == 9) + }//for (i=0; i<ru->nb_tx; i++) + }//if(proc->frame_tx == print_frame) + }//else emulate_rf + + proc->emulate_rf_busy = 0; + }//if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) + } + + printf( "Exiting ru_thread \n"); + + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW,"Could not stop the RF device\n"); + else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); + } + + ru_thread_status = 0; + return &ru_thread_status; +} +/* +// This thread run the initial synchronization like a UE +void *ru_thread_synch(void *arg) { + + RU_t *ru = (RU_t*)arg; + NR_DL_FRAME_PARMS *fp=ru->nr_frame_parms; + int32_t sync_pos,sync_pos2; + uint32_t peak_val; + uint32_t sync_corr[307200] __attribute__((aligned(32))); + static int ru_thread_synch_status; + + + + wait_sync("ru_thread_synch"); + + // initialize variables for PSS detection + lte_sync_time_init(ru->nr_frame_parms); + + while (!oai_exit) { + + // wait to be woken up + if (wait_on_condition(&ru->proc.mutex_synch,&ru->proc.cond_synch,&ru->proc.instance_cnt_synch,"ru_thread_synch")<0) break; + + // if we're not in synch, then run initial synch + if (ru->in_synch == 0) { + // run intial synch like UE + LOG_I(PHY,"Running initial synchronization\n"); + + sync_pos = lte_sync_time_gNB(ru->common.rxdata, + fp, + fp->samples_per_subframe*5, + &peak_val, + sync_corr); + LOG_I(PHY,"RU synch: %d, val %d\n",sync_pos,peak_val); + + if (sync_pos >= 0) { + if (sync_pos >= fp->nb_prefix_samples) + sync_pos2 = sync_pos - fp->nb_prefix_samples; + else + sync_pos2 = sync_pos + (fp->samples_per_subframe*10) - fp->nb_prefix_samples; + + if (fp->frame_type == FDD) { + + // PSS is hypothesized in last symbol of first slot in Frame + int sync_pos_slot = (fp->samples_per_subframe>>1) - fp->ofdm_symbol_size - fp->nb_prefix_samples; + + if (sync_pos2 >= sync_pos_slot) + ru->rx_offset = sync_pos2 - sync_pos_slot; + else + ru->rx_offset = (fp->samples_per_subframe*10) + sync_pos2 - sync_pos_slot; + } + else { + + } + + LOG_I(PHY,"Estimated sync_pos %d, peak_val %d => timing offset %d\n",sync_pos,peak_val,ru->rx_offset); + + if ((peak_val > 300000) && (sync_pos > 0)) { + // if (sync_pos++ > 3) { + write_output("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_subframe*5,1,2); + write_output("ru_rx.m","rxs",(void*)ru->ru_time.rxdata[0][0],fp->samples_per_subframe*10,1,1); + exit(-1); + } + + ru->in_synch=1; + } + } + + if (release_thread(&ru->proc.mutex_synch,&ru->proc.instance_cnt_synch,"ru_synch_thread") < 0) break; + } // oai_exit + + ru_thread_synch_status = 0; + return &ru_thread_synch_status; + +} +*/ + +int start_if(struct RU_t_s *ru,struct PHY_VARS_gNB_s *gNB) { + return(ru->ifdevice.trx_start_func(&ru->ifdevice)); +} + +int start_rf(RU_t *ru) { + return(ru->rfdevice.trx_start_func(&ru->rfdevice)); +} + +int stop_rf(RU_t *ru) { + ru->rfdevice.trx_end_func(&ru->rfdevice); + return 0; +} + +extern void fep_full(RU_t *ru); +extern void ru_fep_full_2thread(RU_t *ru); +extern void nr_feptx_ofdm(RU_t *ru); +extern void nr_feptx_ofdm_2thread(RU_t *ru); +extern void feptx_prec(RU_t *ru); +extern void init_fep_thread(RU_t *ru); +extern void init_nr_feptx_thread(RU_t *ru); + +void init_RU_proc(RU_t *ru) { + int i=0; + RU_proc_t *proc; + char name[100]; +#ifndef OCP_FRAMEWORK + LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]); +#endif + proc = &ru->proc; + memset((void *)proc,0,sizeof(RU_proc_t)); + proc->ru = ru; + proc->instance_cnt_prach = -1; + proc->instance_cnt_synch = -1; ; + proc->instance_cnt_FH = -1; + proc->instance_cnt_FH1 = -1; + proc->instance_cnt_gNBs = -1; + proc->instance_cnt_asynch_rxtx = -1; + proc->instance_cnt_emulateRF = -1; + proc->first_rx = 1; + proc->first_tx = 1; + proc->frame_offset = 0; + proc->num_slaves = 0; + proc->frame_tx_unwrap = 0; + + for (i=0; i<10; i++) proc->symbol_mask[i]=0; + + pthread_mutex_init( &proc->mutex_prach, NULL); + pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL); + pthread_mutex_init( &proc->mutex_synch,NULL); + pthread_mutex_init( &proc->mutex_FH,NULL); + pthread_mutex_init( &proc->mutex_FH1,NULL); + pthread_mutex_init( &proc->mutex_emulateRF,NULL); + pthread_mutex_init( &proc->mutex_gNBs, NULL); + pthread_cond_init( &proc->cond_prach, NULL); + pthread_cond_init( &proc->cond_FH, NULL); + pthread_cond_init( &proc->cond_FH1, NULL); + pthread_cond_init( &proc->cond_emulateRF, NULL); + pthread_cond_init( &proc->cond_asynch_rxtx, NULL); + pthread_cond_init( &proc->cond_synch,NULL); + pthread_cond_init( &proc->cond_gNBs, NULL); + threadCreate( &proc->pthread_FH, ru_thread, (void *)ru, "thread_FH", -1, OAI_PRIORITY_RT_MAX ); + + if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) + threadCreate( &proc->pthread_FH1, ru_thread_tx, (void *)ru, "thread_FH1", -1, OAI_PRIORITY_RT ); + + if(emulate_rf) + threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT ); + + if (ru->function == NGFI_RRU_IF4p5) { + threadCreate( &proc->pthread_prach, ru_thread_prach, (void *)ru, "RACH", -1, OAI_PRIORITY_RT ); + ///tmp deactivation of synch thread + // if (ru->is_slave == 1) pthread_create( &proc->pthread_synch, attr_synch, ru_thread_synch, (void*)ru); + + if ((ru->if_timing == synch_to_other) || + (ru->function == NGFI_RRU_IF5) || + (ru->function == NGFI_RRU_IF4p5)) threadCreate( &proc->pthread_asynch_rxtx, ru_thread_asynch_rxtx, (void *)ru, "asynch_rxtx", -1, OAI_PRIORITY_RT ); + + snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx ); + pthread_setname_np( proc->pthread_FH, name ); + } else if (ru->function == gNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF + LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__); + threadCreate( &proc->pthread_prach, ru_thread_prach, (void *)ru,"RACH", -1, OAI_PRIORITY_RT ); + } + + if (get_nprocs()>=2) { + if (ru->feprx) init_fep_thread(ru); + + if (ru->feptx_ofdm) nr_init_feptx_thread(ru); + } + + if (opp_enabled == 1) threadCreate(&ru->ru_stats_thread,ru_stats_thread,(void *)ru, "emulateRF", -1, OAI_PRIORITY_RT_LOW); +} + +void kill_RU_proc(int inst) { + RU_t *ru = RC.ru[inst]; + RU_proc_t *proc = &ru->proc; + pthread_mutex_lock(&proc->mutex_FH); + proc->instance_cnt_FH = 0; + pthread_mutex_unlock(&proc->mutex_FH); + pthread_cond_signal(&proc->cond_FH); + pthread_mutex_lock(&proc->mutex_prach); + proc->instance_cnt_prach = 0; + pthread_mutex_unlock(&proc->mutex_prach); + pthread_cond_signal(&proc->cond_prach); + pthread_mutex_lock(&proc->mutex_synch); + proc->instance_cnt_synch = 0; + pthread_mutex_unlock(&proc->mutex_synch); + pthread_cond_signal(&proc->cond_synch); + pthread_mutex_lock(&proc->mutex_gNBs); + proc->instance_cnt_gNBs = 0; + pthread_mutex_unlock(&proc->mutex_gNBs); + pthread_cond_signal(&proc->cond_gNBs); + pthread_mutex_lock(&proc->mutex_asynch_rxtx); + proc->instance_cnt_asynch_rxtx = 0; + pthread_mutex_unlock(&proc->mutex_asynch_rxtx); + pthread_cond_signal(&proc->cond_asynch_rxtx); + LOG_D(PHY, "Joining pthread_FH\n"); + pthread_join(proc->pthread_FH, NULL); + + if (ru->function == NGFI_RRU_IF4p5) { + LOG_D(PHY, "Joining pthread_prach\n"); + pthread_join(proc->pthread_prach, NULL); + + if (ru->is_slave) { + LOG_D(PHY, "Joining pthread_\n"); + pthread_join(proc->pthread_synch, NULL); + } + + if ((ru->if_timing == synch_to_other) || + (ru->function == NGFI_RRU_IF5) || + (ru->function == NGFI_RRU_IF4p5)) { + LOG_D(PHY, "Joining pthread_asynch_rxtx\n"); + pthread_join(proc->pthread_asynch_rxtx, NULL); + } + } + + if (get_nprocs() >= 2) { + if (ru->feprx) { + pthread_mutex_lock(&proc->mutex_fep); + proc->instance_cnt_fep = 0; + pthread_mutex_unlock(&proc->mutex_fep); + pthread_cond_signal(&proc->cond_fep); + LOG_D(PHY, "Joining pthread_fep\n"); + pthread_join(proc->pthread_fep, NULL); + pthread_mutex_destroy(&proc->mutex_fep); + pthread_cond_destroy(&proc->cond_fep); + } + + if (ru->feptx_ofdm) { + pthread_mutex_lock(&proc->mutex_feptx); + proc->instance_cnt_feptx = 0; + pthread_mutex_unlock(&proc->mutex_feptx); + pthread_cond_signal(&proc->cond_feptx); + LOG_D(PHY, "Joining pthread_feptx\n"); + pthread_join(proc->pthread_feptx, NULL); + pthread_mutex_destroy(&proc->mutex_feptx); + pthread_cond_destroy(&proc->cond_feptx); + } + } + + if (opp_enabled) { + LOG_D(PHY, "Joining ru_stats_thread\n"); + pthread_join(ru->ru_stats_thread, NULL); + } + + pthread_mutex_destroy(&proc->mutex_prach); + pthread_mutex_destroy(&proc->mutex_asynch_rxtx); + pthread_mutex_destroy(&proc->mutex_synch); + pthread_mutex_destroy(&proc->mutex_FH); + pthread_mutex_destroy(&proc->mutex_gNBs); + pthread_cond_destroy(&proc->cond_prach); + pthread_cond_destroy(&proc->cond_FH); + pthread_cond_destroy(&proc->cond_asynch_rxtx); + pthread_cond_destroy(&proc->cond_synch); + pthread_cond_destroy(&proc->cond_gNBs); +} + +int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { + FH_fmt_options_t fmt = cap->FH_fmt; + int i; + int found_band=0; + LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->nr_frame_parms->eutra_band); + + for (i=0; i<cap->num_bands; i++) { + LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx); + + if (ru->nr_frame_parms->eutra_band == cap->band_list[i]) { + found_band=1; + break; + } + } + + if (found_band == 0) { + LOG_I(PHY,"Couldn't find target EUTRA band %d on RRU %d\n",ru->nr_frame_parms->eutra_band,ru->idx); + return(-1); + } + + switch (ru->if_south) { + case LOCAL_RF: + AssertFatal(1==0, "This RU should not have a local RF, exiting\n"); + return(0); + break; + + case REMOTE_IF5: + if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0); + + break; + + case REMOTE_IF4p5: + if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0); + + break; + + case REMOTE_MBP_IF5: + if (fmt == MBP_IF5) return(0); + + break; + + default: + LOG_I(PHY,"No compatible Fronthaul interface found for RRU %d\n", ru->idx); + return(-1); + } + + return(-1); +} + + +char rru_format_options[4][20] = {"OAI_IF5_only","OAI_IF4p5_only","OAI_IF5_and_IF4p5","MBP_IF5"}; + +char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"}; +char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"}; + +void configure_ru(int idx, + void *arg) { + RU_t *ru = RC.ru[idx]; + RRU_config_t *config = (RRU_config_t *)arg; + RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg; + nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config; + int ret; + LOG_I(PHY, "Received capabilities from RRU %d\n",idx); + + if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]); + + AssertFatal((ret=check_capabilities(ru,capabilities)) == 0, + "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret); + // take antenna capabilities of RRU + ru->nb_tx = capabilities->nb_tx[0]; + ru->nb_rx = capabilities->nb_rx[0]; + // Pass configuration to RRU + LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->nr_frame_parms->eutra_band); + // wait for configuration + config->FH_fmt = ru->if_south; + config->num_bands = 1; + config->band_list[0] = ru->nr_frame_parms->eutra_band; + config->tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq; + config->rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq; + //config->tdd_config[0] = ru->nr_frame_parms->tdd_config; + //config->tdd_config_S[0] = ru->nr_frame_parms->tdd_config_S; + config->att_tx[0] = ru->att_tx; + config->att_rx[0] = ru->att_rx; + config->N_RB_DL[0] = gNB_config->rf_config.dl_carrier_bandwidth.value; + config->N_RB_UL[0] = gNB_config->rf_config.ul_carrier_bandwidth.value; + config->threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs; + /* if (ru->if_south==REMOTE_IF4p5) { + config->prach_FreqOffset[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; + config->prach_ConfigIndex[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; + LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);*/ + nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, ru->nr_frame_parms); + nr_phy_init_RU(ru); +} + +void configure_rru(int idx, + void *arg) { + RRU_config_t *config = (RRU_config_t *)arg; + RU_t *ru = RC.ru[idx]; + nfapi_nr_config_request_t *gNB_config = &ru->gNB_list[0]->gNB_config; + ru->nr_frame_parms->eutra_band = config->band_list[0]; + ru->nr_frame_parms->dl_CarrierFreq = config->tx_freq[0]; + ru->nr_frame_parms->ul_CarrierFreq = config->rx_freq[0]; + + if (ru->nr_frame_parms->dl_CarrierFreq == ru->nr_frame_parms->ul_CarrierFreq) { + gNB_config->subframe_config.duplex_mode.value = TDD; + //ru->nr_frame_parms->tdd_config = config->tdd_config[0]; + //ru->nr_frame_parms->tdd_config_S = config->tdd_config_S[0]; + } else + gNB_config->subframe_config.duplex_mode.value = FDD; + + ru->att_tx = config->att_tx[0]; + ru->att_rx = config->att_rx[0]; + gNB_config->rf_config.dl_carrier_bandwidth.value = config->N_RB_DL[0]; + gNB_config->rf_config.ul_carrier_bandwidth.value = config->N_RB_UL[0]; + ru->nr_frame_parms->threequarter_fs = config->threequarter_fs[0]; + + //ru->nr_frame_parms->pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0]; + if (ru->function==NGFI_RRU_IF4p5) { + ru->nr_frame_parms->att_rx = ru->att_rx; + ru->nr_frame_parms->att_tx = ru->att_tx; + /* + LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n", + config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx); + ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0]; + ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; */ + } + + fill_rf_config(ru,ru->rf_config_file); + nr_init_frame_parms(&ru->gNB_list[0]->gNB_config, ru->nr_frame_parms); + nr_phy_init_RU(ru); +} + +/* +void init_precoding_weights(PHY_VARS_gNB *gNB) { + + int layer,ru_id,aa,re,ue,tb; + LTE_DL_FRAME_PARMS *fp=&gNB->frame_parms; + RU_t *ru; + LTE_gNB_DLSCH_t *dlsch; + + // init precoding weigths + for (ue=0;ue<NUMBER_OF_UE_MAX;ue++) { + for (tb=0;tb<2;tb++) { + dlsch = gNB->dlsch[ue][tb]; + for (layer=0; layer<4; layer++) { + int nb_tx=0; + for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { + ru = RC.ru[ru_id]; + nb_tx+=ru->nb_tx; + } + dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(nb_tx*sizeof(int32_t*)); + + for (aa=0; aa<nb_tx; aa++) { + dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t)); + for (re=0;re<fp->ofdm_symbol_size; re++) { + dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff; + } + } + } + } + } +}*/ + +void set_function_spec_param(RU_t *ru) { + int ret; + + switch (ru->if_south) { + case LOCAL_RF: // this is an RU with integrated RF (RRU, gNB) + if (ru->function == NGFI_RRU_IF5) { // IF5 RRU + ru->do_prach = 0; // no prach processing in RU + ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north + ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously + ru->feprx = NULL; // nothing (this is a time-domain signal) + ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal) + ru->feptx_prec = NULL; // nothing (this is a time-domain signal) + ru->start_if = start_if; // need to start the if interface for if5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + } else if (ru->function == NGFI_RRU_IF4p5) { + ru->do_prach = 1; // do part of prach processing in RU + ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north + ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception + ru->fh_south_out = tx_rf; // send output to RF + ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously + ru->feprx = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // this is fep with idft only (no precoding in RRU) + ru->feptx_prec = NULL; + ru->start_if = start_if; // need to start the if interface for if4p5 + ru->ifdevice.host_type = RRU_HOST; + ru->rfdevice.host_type = RRU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + reset_meas(&ru->rx_fhaul); + reset_meas(&ru->tx_fhaul); + reset_meas(&ru->compression); + reset_meas(&ru->transport); + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + malloc_IF4p5_buffer(ru); + } else if (ru->function == gNodeB_3GPP) { + ru->do_prach = 0; // no prach processing in RU + ru->feprx = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread; // RX DFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // this is fep with idft and precoding + ru->feptx_prec = feptx_prec; // this is fep with idft and precoding + ru->fh_north_in = NULL; // no incoming fronthaul from north + ru->fh_north_out = NULL; // no outgoing fronthaul to north + ru->start_if = NULL; // no if interface + ru->rfdevice.host_type = RAU_HOST; + } + + ru->fh_south_in = rx_rf; // local synchronous RF RX + ru->fh_south_out = tx_rf; // local synchronous RF TX + ru->start_rf = start_rf; // need to start the local RF interface + ru->stop_rf = stop_rf; + printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf); + /* + if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise + fill_rf_config(ru,rf_config_file); + init_frame_parms(&ru->frame_parms,1); + nr_phy_init_RU(ru); + } + + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + if (setup_RU_buffers(ru)!=0) { + printf("Exiting, cannot initialize RU Buffers\n"); + exit(-1); + }*/ + break; + + case REMOTE_IF5: // the remote unit is IF5 RRU + ru->do_prach = 0; + ru->feprx = (get_nprocs()<=2) ? fep_full : fep_full; // this is frequency-shift + DFTs + ru->feptx_prec = feptx_prec; // need to do transmit Precoding + IDFTs + ru->feptx_ofdm = (get_nprocs()<=2) ? nr_feptx_ofdm : nr_feptx_ofdm_2thread; // need to do transmit Precoding + IDFTs + ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception + ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission + ru->fh_south_asynch_in = NULL; // no asynchronous UL + ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; + ru->start_if = start_if; // need to start if interface for IF5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + break; + + case REMOTE_IF4p5: + ru->do_prach = 0; + ru->feprx = NULL; // DFTs + ru->feptx_prec = feptx_prec; // Precoding operation + ru->feptx_ofdm = NULL; // no OFDM mod + ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception + ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission + ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other + ru->fh_north_out = NULL; + ru->fh_north_asynch_in = NULL; + ru->start_rf = NULL; // no local RF + ru->stop_rf = NULL; + ru->start_if = start_if; // need to start if interface for IF4p5 + ru->ifdevice.host_type = RAU_HOST; + ru->ifdevice.eth_params = &ru->eth_params; + ru->ifdevice.configure_rru = configure_ru; + ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); + printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx); + + if (ret<0) { + printf("Exiting, cannot initialize transport protocol\n"); + exit(-1); + } + + malloc_IF4p5_buffer(ru); + break; + + default: + LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); + break; + } // switch on interface type +} + +extern void RCconfig_RU(void); + +void init_RU(char *rf_config_file) { + int ru_id; + RU_t *ru; + PHY_VARS_gNB *gNB0= (PHY_VARS_gNB *)NULL; + NR_DL_FRAME_PARMS *fp = (NR_DL_FRAME_PARMS *)NULL; + int i; + int CC_id; + // create status mask + RC.ru_mask = 0; + pthread_mutex_init(&RC.ru_mutex,NULL); + pthread_cond_init(&RC.ru_cond,NULL); + // read in configuration file) + printf("configuring RU from file\n"); + RCconfig_RU(); + LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_nr_L1_inst,RC.nb_RU,get_nprocs()); + + if (RC.nb_nr_CC != 0) + for (i=0; i<RC.nb_nr_L1_inst; i++) + for (CC_id=0; CC_id<RC.nb_nr_CC[i]; CC_id++) RC.gNB[i][CC_id]->num_RU=0; + + LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + LOG_D(PHY,"Process RC.ru[%d]\n",ru_id); + ru = RC.ru[ru_id]; + ru->rf_config_file = rf_config_file; + ru->idx = ru_id; + ru->ts_offset = 0; + // use gNB_list[0] as a reference for RU frame parameters + // NOTE: multiple CC_id are not handled here yet! + + if (ru->num_gNB > 0) { + LOG_D(PHY, "%s() RC.ru[%d].num_gNB:%d ru->gNB_list[0]:%p RC.gNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_gNB, ru->gNB_list[0], RC.gNB[0][0], ru->rf_config_file); + + if (ru->gNB_list[0] == 0) { + LOG_E(PHY,"%s() DJP - ru->gNB_list ru->num_gNB are not initialized - so do it manually\n", __FUNCTION__); + ru->gNB_list[0] = RC.gNB[0][0]; + ru->num_gNB=1; + // + // DJP - feptx_prec() / feptx_ofdm() parses the gNB_list (based on num_gNB) and copies the txdata_F to txdata in RU + // + } else { + LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__); + } + } + + gNB0 = ru->gNB_list[0]; + fp = ru->nr_frame_parms; + LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); + + if (gNB0) { + if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) + AssertFatal(gNB0!=NULL,"gNB0 is null!\n"); + + if (gNB0) { + LOG_I(PHY,"Copying frame parms from gNB %d to ru %d\n",gNB0->Mod_id,ru->idx); + memcpy((void *)fp,(void *)&gNB0->frame_parms,sizeof(NR_DL_FRAME_PARMS)); + memset((void *)ru->frame_parms, 0, sizeof(LTE_DL_FRAME_PARMS)); + // attach all RU to all gNBs in its list/ + LOG_D(PHY,"ru->num_gNB:%d gNB0->num_RU:%d\n", ru->num_gNB, gNB0->num_RU); + + for (i=0; i<ru->num_gNB; i++) { + gNB0 = ru->gNB_list[i]; + gNB0->RU_list[gNB0->num_RU++] = ru; + } + } + } + + // LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],gNB_timing[ru->if_timing],ru->function); + set_function_spec_param(ru); + LOG_I(PHY,"Starting ru_thread %d\n",ru_id); + init_RU_proc(ru); + } // for ru_id + + // sleep(1); + LOG_D(HW,"[nr-softmodem.c] RU threads created\n"); +} + + + + +void stop_RU(int nb_ru) { + for (int inst = 0; inst < nb_ru; inst++) { + LOG_I(PHY, "Stopping RU %d processing threads\n", inst); + kill_RU_proc(inst); + } +} + + +/* --------------------------------------------------------*/ +/* from here function to use configuration module */ +void RCconfig_RU(void) { + int j = 0; + int i = 0; + paramdef_t RUParams[] = RUPARAMS_DESC; + paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; + config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL); + + if ( RUParamList.numelt > 0) { + RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); + RC.ru_mask=(1<<NB_RU) - 1; + printf("Set RU mask to %lx\n",RC.ru_mask); + + for (j = 0; j < RC.nb_RU; j++) { + RC.ru[j] = (RU_t *)malloc(sizeof(RU_t)); + memset((void *)RC.ru[j],0,sizeof(RU_t)); + RC.ru[j]->idx = j; + RC.ru[j]->nr_frame_parms = (NR_DL_FRAME_PARMS *)malloc(sizeof(NR_DL_FRAME_PARMS)); + RC.ru[j]->frame_parms = (LTE_DL_FRAME_PARMS *)malloc(sizeof(LTE_DL_FRAME_PARMS)); + printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]); + RC.ru[j]->if_timing = synch_to_ext_device; + + if (RC.nb_nr_L1_inst >0) + RC.ru[j]->num_gNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; + else + RC.ru[j]->num_gNB = 0; + + for (i=0; i<RC.ru[j]->num_gNB; i++) RC.ru[j]->gNB_list[i] = RC.gNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0]; + + if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) { + RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); + } + + if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) { + if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) { + RC.ru[j]->openair0_cfg.clock_source = internal; + LOG_D(PHY, "RU clock source set as internal\n"); + } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) { + RC.ru[j]->openair0_cfg.clock_source = external; + LOG_D(PHY, "RU clock source set as external\n"); + } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) { + RC.ru[j]->openair0_cfg.clock_source = gpsdo; + LOG_D(PHY, "RU clock source set as gpsdo\n"); + } else { + LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); + } + } + + if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { + if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = gNodeB_3GPP; + printf("Setting function for RU %d to gNodeB_3GPP\n",j); + } else { + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j); + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = LOCAL_RF; + RC.ru[j]->function = NGFI_RRU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j); + } + } + + RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; + RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); + RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; + + for (i=0; i<RC.ru[j]->num_bands; i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; + } //strcmp(local_rf, "yes") == 0 + else { + printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); + RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); + RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); + RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); + RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); + RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); + RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); + + if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { + RC.ru[j]->if_south = REMOTE_IF4p5; + RC.ru[j]->function = NGFI_RAU_IF4p5; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) { + RC.ru[j]->if_south = REMOTE_IF5; + RC.ru[j]->function = NGFI_RAU_IF5; + RC.ru[j]->if_timing = synch_to_other; + RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS; + } + } /* strcmp(local_rf, "yes") != 0 */ + + RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); + RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); + RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); + RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); + }// j=0..num_rus + } else { + RC.nb_RU = 0; + } // setting != NULL + + return; +} diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c new file mode 100644 index 0000000000000000000000000000000000000000..3147284e997b1c01b66a78bb7773817e6d30fa27 --- /dev/null +++ b/executables/nr-softmodem.c @@ -0,0 +1,1237 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + + +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include <sched.h> + + +#include "T.h" + +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +#include <common/utils/assertions.h> + +#include "msc.h" + +#include "PHY/types.h" +#include "common/ran_context.h" + +#include "PHY/defs_gNB.h" +#include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "../../ARCH/COMMON/common_lib.h" +#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h" + +//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all + +#include "PHY/phy_vars.h" +#include "SCHED/sched_common_vars.h" +#include "LAYER2/MAC/mac_vars.h" + +#include "LAYER2/MAC/mac.h" +#include "LAYER2/MAC/mac_proto.h" +#include "RRC/LTE/rrc_vars.h" +#include "PHY_INTERFACE/phy_interface_vars.h" +#include "gnb_config.h" + +#ifdef SMBV +#include "PHY/TOOLS/smbv.h" +unsigned short config_frames[4] = {2,9,11,13}; +#endif + +#include "common/utils/LOG/log.h" +#include "common/utils/LOG/vcd_signal_dumper.h" + +#include "UTIL/OPT/opt.h" + +//#include "PHY/TOOLS/time_meas.h" + +#ifndef OPENAIR2 + #include "UTIL/OTG/otg_vars.h" +#endif + +#if defined(ENABLE_ITTI) + #include "intertask_interface.h" +#endif + +#include "PHY/INIT/phy_init.h" + +#include "system.h" +#include <openair2/GNB_APP/gnb_app.h> + +#ifdef XFORMS + #include "PHY/TOOLS/nr_phy_scope.h" + #include "stats.h" +#endif +#include "nr-softmodem.h" +#include "NB_IoT_interface.h" + +#ifdef XFORMS + // current status is that every UE has a DL scope for a SINGLE eNB (gnb_id=0) + // at eNB 0, an UL scope for every UE + + FD_phy_scope_gnb *form_gnb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; + FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; + char title[255]; + unsigned char scope_enb_num_ue = 2; + static pthread_t forms_thread; //xforms + +#endif //XFORMS + +short nr_mod_table[NR_MOD_TABLE_SIZE_SHORT] = {0,0,16384,16384,-16384,-16384,16384,16384,16384,-16384,-16384,16384,-16384,-16384,7327,7327,7327,21981,21981,7327,21981,21981,7327,-7327,7327,-21981,21981,-7327,21981,-21981,-7327,7327,-7327,21981,-21981,7327,-21981,21981,-7327,-7327,-7327,-21981,-21981,-7327,-21981,-21981,10726,10726,10726,3576,3576,10726,3576,3576,10726,17876,10726,25027,3576,17876,3576,25027,17876,10726,17876,3576,25027,10726,25027,3576,17876,17876,17876,25027,25027,17876,25027,25027,10726,-10726,10726,-3576,3576,-10726,3576,-3576,10726,-17876,10726,-25027,3576,-17876,3576,-25027,17876,-10726,17876,-3576,25027,-10726,25027,-3576,17876,-17876,17876,-25027,25027,-17876,25027,-25027,-10726,10726,-10726,3576,-3576,10726,-3576,3576,-10726,17876,-10726,25027,-3576,17876,-3576,25027,-17876,10726,-17876,3576,-25027,10726,-25027,3576,-17876,17876,-17876,25027,-25027,17876,-25027,25027,-10726,-10726,-10726,-3576,-3576,-10726,-3576,-3576,-10726,-17876,-10726,-25027,-3576,-17876,-3576,-25027,-17876,-10726,-17876,-3576,-25027,-10726,-25027,-3576,-17876,-17876,-17876,-25027,-25027,-17876,-25027,-25027,8886,8886,8886,12439,12439,8886,12439,12439,8886,5332,8886,1778,12439,5332,12439,1778,5332,8886,5332,12439,1778,8886,1778,12439,5332,5332,5332,1778,1778,5332,1778,1778,8886,19547,8886,15993,12439,19547,12439,15993,8886,23101,8886,26655,12439,23101,12439,26655,5332,19547,5332,15993,1778,19547,1778,15993,5332,23101,5332,26655,1778,23101,1778,26655,19547,8886,19547,12439,15993,8886,15993,12439,19547,5332,19547,1778,15993,5332,15993,1778,23101,8886,23101,12439,26655,8886,26655,12439,23101,5332,23101,1778,26655,5332,26655,1778,19547,19547,19547,15993,15993,19547,15993,15993,19547,23101,19547,26655,15993,23101,15993,26655,23101,19547,23101,15993,26655,19547,26655,15993,23101,23101,23101,26655,26655,23101,26655,26655,8886,-8886,8886,-12439,12439,-8886,12439,-12439,8886,-5332,8886,-1778,12439,-5332,12439,-1778,5332,-8886,5332,-12439,1778,-8886,1778,-12439,5332,-5332,5332,-1778,1778,-5332,1778,-1778,8886,-19547,8886,-15993,12439,-19547,12439,-15993,8886,-23101,8886,-26655,12439,-23101,12439,-26655,5332,-19547,5332,-15993,1778,-19547,1778,-15993,5332,-23101,5332,-26655,1778,-23101,1778,-26655,19547,-8886,19547,-12439,15993,-8886,15993,-12439,19547,-5332,19547,-1778,15993,-5332,15993,-1778,23101,-8886,23101,-12439,26655,-8886,26655,-12439,23101,-5332,23101,-1778,26655,-5332,26655,-1778,19547,-19547,19547,-15993,15993,-19547,15993,-15993,19547,-23101,19547,-26655,15993,-23101,15993,-26655,23101,-19547,23101,-15993,26655,-19547,26655,-15993,23101,-23101,23101,-26655,26655,-23101,26655,-26655,-8886,8886,-8886,12439,-12439,8886,-12439,12439,-8886,5332,-8886,1778,-12439,5332,-12439,1778,-5332,8886,-5332,12439,-1778,8886,-1778,12439,-5332,5332,-5332,1778,-1778,5332,-1778,1778,-8886,19547,-8886,15993,-12439,19547,-12439,15993,-8886,23101,-8886,26655,-12439,23101,-12439,26655,-5332,19547,-5332,15993,-1778,19547,-1778,15993,-5332,23101,-5332,26655,-1778,23101,-1778,26655,-19547,8886,-19547,12439,-15993,8886,-15993,12439,-19547,5332,-19547,1778,-15993,5332,-15993,1778,-23101,8886,-23101,12439,-26655,8886,-26655,12439,-23101,5332,-23101,1778,-26655,5332,-26655,1778,-19547,19547,-19547,15993,-15993,19547,-15993,15993,-19547,23101,-19547,26655,-15993,23101,-15993,26655,-23101,19547,-23101,15993,-26655,19547,-26655,15993,-23101,23101,-23101,26655,-26655,23101,-26655,26655,-8886,-8886,-8886,-12439,-12439,-8886,-12439,-12439,-8886,-5332,-8886,-1778,-12439,-5332,-12439,-1778,-5332,-8886,-5332,-12439,-1778,-8886,-1778,-12439,-5332,-5332,-5332,-1778,-1778,-5332,-1778,-1778,-8886,-19547,-8886,-15993,-12439,-19547,-12439,-15993,-8886,-23101,-8886,-26655,-12439,-23101,-12439,-26655,-5332,-19547,-5332,-15993,-1778,-19547,-1778,-15993,-5332,-23101,-5332,-26655,-1778,-23101,-1778,-26655,-19547,-8886,-19547,-12439,-15993,-8886,-15993,-12439,-19547,-5332,-19547,-1778,-15993,-5332,-15993,-1778,-23101,-8886,-23101,-12439,-26655,-8886,-26655,-12439,-23101,-5332,-23101,-1778,-26655,-5332,-26655,-1778,-19547,-19547,-19547,-15993,-15993,-19547,-15993,-15993,-19547,-23101,-19547,-26655,-15993,-23101,-15993,-26655,-23101,-19547,-23101,-15993,-26655,-19547,-26655,-15993,-23101,-23101,-23101,-26655,-26655,-23101,-26655,-26655}; + + +pthread_cond_t nfapi_sync_cond; +pthread_mutex_t nfapi_sync_mutex; +int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex + +uint8_t nfapi_mode = 0; // Default to monolithic mode + +pthread_cond_t sync_cond; +pthread_mutex_t sync_mutex; +int sync_var=-1; //!< protected by mutex \ref sync_mutex. +int config_sync_var=-1; + +#if defined(ENABLE_ITTI) + volatile int start_gNB = 0; +#endif +volatile int oai_exit = 0; + +static clock_source_t clock_source = internal; +static int wait_for_sync = 0; + +unsigned int mmapped_dma=0; +int single_thread_flag=1; + +static int8_t threequarter_fs=0; + +uint32_t downlink_frequency[MAX_NUM_CCs][4]; +int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +//Temp fix for inexisting NR upper layer +unsigned char NB_gNB_INST = 1; + +#if defined(ENABLE_ITTI) + static char *itti_dump_file = NULL; +#endif + +int UE_scan = 1; +int UE_scan_carrier = 0; +runmode_t mode = normal_txrx; + +FILE *input_fd=NULL; + + +#if MAX_NUM_CCs == 1 +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}}; +#else +rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}}; +double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}}; +double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}}; +#endif + +double rx_gain_off = 0.0; + +double sample_rate=30.72e6; +double bw = 10.0e6; + +static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; + +char rf_config_file[1024]="/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; + +int chain_offset=0; +int phy_test = 0; +uint8_t usim_test = 0; + +uint8_t dci_Format = 0; +uint8_t agregation_Level =0xFF; + +uint8_t nb_antenna_tx = 1; +uint8_t nb_antenna_rx = 1; + +char ref[128] = "internal"; +char channels[128] = "0"; + +int rx_input_level_dBm; + +#ifdef XFORMS + extern int otg_enabled; + static char do_forms=0; +#else + int otg_enabled; +#endif +//int number_of_cards = 1; + + +//static NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]; +//static nfapi_nr_config_request_t *config[MAX_NUM_CCs]; +uint32_t target_dl_mcs = 28; //maximum allowed mcs +uint32_t target_ul_mcs = 20; +uint32_t timing_advance = 0; +uint8_t exit_missed_slots=1; +uint64_t num_missed_slots=0; // counter for the number of missed slots + + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + +extern void init_eNB_afterRU(void); + +int transmission_mode=1; +int emulate_rf = 0; +int numerology = 0; +char *parallel_config = NULL; +char *worker_config = NULL; + +static THREAD_STRUCT thread_struct; +void set_parallel_conf(char *parallel_conf) { + if(strcmp(parallel_conf,"PARALLEL_SINGLE_THREAD")==0) thread_struct.parallel_conf = PARALLEL_SINGLE_THREAD; + else if(strcmp(parallel_conf,"PARALLEL_RU_L1_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_SPLIT; + else if(strcmp(parallel_conf,"PARALLEL_RU_L1_TRX_SPLIT")==0) thread_struct.parallel_conf = PARALLEL_RU_L1_TRX_SPLIT; + + printf("[CONFIG] parallel conf is set to %d\n",thread_struct.parallel_conf); +} +void set_worker_conf(char *worker_conf) { + if(strcmp(worker_conf,"WORKER_DISABLE")==0) thread_struct.worker_conf = WORKER_DISABLE; + else if(strcmp(worker_conf,"WORKER_ENABLE")==0) thread_struct.worker_conf = WORKER_ENABLE; + + printf("[CONFIG] worker conf is set to %d\n",thread_struct.worker_conf); +} +PARALLEL_CONF_t get_thread_parallel_conf(void) { + return thread_struct.parallel_conf; +} +WORKER_CONF_t get_thread_worker_conf(void) { + return thread_struct.worker_conf; +} + + +/* struct for ethernet specific parameters given in eNB conf file */ +eth_params_t *eth_params; + +openair0_config_t openair0_cfg[MAX_CARDS]; + +double cpuf; + +extern char uecap_xer[1024]; +char uecap_xer_in=0; + +/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed + * this is very hackish - find a proper solution + */ +uint8_t abstraction_flag=0; + +/* forward declarations */ +void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); + +/*---------------------BMC: timespec helpers -----------------------------*/ + +struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; +struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + +struct timespec clock_difftime(struct timespec start, struct timespec end) { + struct timespec temp; + + if ((end.tv_nsec-start.tv_nsec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_nsec = end.tv_nsec-start.tv_nsec; + } + + return temp; +} + +void print_difftimes(void) { +#ifdef DEBUG + printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#else + LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); +#endif +} + +void update_difftimes(struct timespec start, struct timespec end) { + struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; + int changed = 0; + diff_time = clock_difftime(start, end); + + if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { + min_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + + if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { + max_diff_time.tv_nsec = diff_time.tv_nsec; + changed = 1; + } + +#if 1 + + if (changed) print_difftimes(); + +#endif +} + +/*------------------------------------------------------------------------*/ + +unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { + return (txi + (txq<<6) + (rxi<<12) + (rxq<<18)); +} +unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) { + return (dcoff_i_rxfe + (dcoff_q_rxfe<<8)); +} + +#if !defined(ENABLE_ITTI) +void signal_handler(int sig) { + void *array[10]; + size_t size; + + if (sig==SIGSEGV) { + // get void*'s for all entries on the stack + size = backtrace(array, 10); + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, 2); + exit(-1); + } else { + printf("trying to exit gracefully...\n"); + oai_exit = 1; + } +} +#endif +#define KNRM "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KBLU "\x1B[34m" +#define RESET "\033[0m" + +#if defined(ENABLE_ITTI) +void signal_handler_itti(int sig) { + // Call exit function + char msg[256]; + memset(msg, 0, 256); + sprintf(msg, "caught signal %s\n", strsignal(sig)); + exit_function(__FILE__, __FUNCTION__, __LINE__, msg); +} +#endif + +void exit_function(const char *file, const char *function, const int line, const char *s) { + int ru_id; + + if (s != NULL) { + printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s); + } + + oai_exit = 1; + + if (RC.ru == NULL) + exit(-1); // likely init not completed, prevent crash or hang, exit now... + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + if (RC.ru[ru_id] && RC.ru[ru_id]->rfdevice.trx_end_func) { + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_end_func = NULL; + } + + if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) { + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_end_func = NULL; + } + } + + sleep(1); //allow lte-softmodem threads to exit first +#if defined(ENABLE_ITTI) + itti_terminate_tasks (TASK_UNKNOWN); +#endif + exit(1); +} + +#ifdef XFORMS + + +void reset_stats(FL_OBJECT *button, long arg) { + PHY_VARS_gNB *phy_vars_gNB = RC.gNB[0][0]; + + for (int i=0; i<NUMBER_OF_UE_MAX; i++) { + for (int k=0; k<8; k++) { //harq_processes + /* for (j=0; j<phy_vars_gNB->dlsch[i][0]->Mlimit; j++) { + phy_vars_gNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_trials[k][j]=0; + }*/ + phy_vars_gNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_consecutive_errors=0; + phy_vars_gNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_gNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_gNB->UE_stats[i].dlsch_mcs_offset=0; + } + } +} + +static void *scope_thread(void *arg) { + int UE_id, CC_id; + int ue_cnt=0; +# ifdef ENABLE_XFORMS_WRITE_STATS + FILE *gNB_stats = fopen("gNB_stats.txt", "w"); +#endif + + while (!oai_exit) { + ue_cnt=0; + + for(UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if ((ue_cnt<scope_enb_num_ue)) { + /* + //this function needs to be written + phy_scope_gNB(form_gnb[CC_id][ue_cnt], + RC.gNB[0][CC_id], + UE_id); + */ + ue_cnt++; + } + } + } + + sleep(1); + } + + // printf("%s",stats_buffer); +# ifdef ENABLE_XFORMS_WRITE_STATS + + if (eNB_stats) { + rewind (gNB_stats); + fwrite (stats_buffer, 1, len, gNB_stats); + fclose (gNB_stats); + } + +# endif + pthread_exit((void *)arg); +} +#endif + + + + +#if defined(ENABLE_ITTI) +void *l2l1_task(void *arg) { + MessageDef *message_p = NULL; + int result; + itti_set_task_real_time(TASK_L2L1); + itti_mark_task_ready(TASK_L2L1); + /* Wait for the initialize message */ + printf("Wait for the ITTI initialize message\n"); + + do { + if (message_p != NULL) { + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } + + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case INITIALIZE_MESSAGE: + /* Start eNB thread */ + LOG_D(EMU, "L2L1 TASK received %s\n", ITTI_MSG_NAME(message_p)); + start_gNB = 1; + break; + + case TERMINATE_MESSAGE: + printf("received terminate message\n"); + oai_exit=1; + start_gNB = 0; + itti_exit_task (); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + } while (ITTI_MSG_ID(message_p) != INITIALIZE_MESSAGE); + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + /* ???? no else but seems to be UE only ??? + do { + // Wait for a message + itti_receive_msg (TASK_L2L1, &message_p); + + switch (ITTI_MSG_ID(message_p)) { + case TERMINATE_MESSAGE: + oai_exit=1; + itti_exit_task (); + break; + + case ACTIVATE_MESSAGE: + start_UE = 1; + break; + + case DEACTIVATE_MESSAGE: + start_UE = 0; + break; + + case MESSAGE_TEST: + LOG_I(EMU, "Received %s\n", ITTI_MSG_NAME(message_p)); + break; + + default: + LOG_E(EMU, "Received unexpected message %s\n", ITTI_MSG_NAME(message_p)); + break; + } + + result = itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p); + AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); + } while(!oai_exit); + */ + return NULL; +} +#endif + +int create_gNB_tasks(uint32_t gnb_nb) { + LOG_D(GNB_APP, "%s(gnb_nb:%d\n", __FUNCTION__, gnb_nb); + itti_wait_ready(1); + + if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { + LOG_E(PDCP, "Create task for L2L1 failed\n"); + return -1; + } + + if (gnb_nb > 0) { + /* Last task to create, others task must be ready before its start */ + if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) { + LOG_E(GNB_APP, "Create task for gNB APP failed\n"); + return -1; + } + } + + /* + # if defined(ENABLE_USE_MME) + if (gnb_nb > 0) { + if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) { + LOG_E(SCTP, "Create task for SCTP failed\n"); + return -1; + } + + if (itti_create_task (TASK_S1AP, s1ap_eNB_task, NULL) < 0) { + LOG_E(S1AP, "Create task for S1AP failed\n"); + return -1; + } + if(!emulate_rf){ + if (itti_create_task (TASK_UDP, udp_eNB_task, NULL) < 0) { + LOG_E(UDP_, "Create task for UDP failed\n"); + return -1; + } + } + + if (itti_create_task (TASK_GTPV1_U, >pv1u_eNB_task, NULL) < 0) { + LOG_E(GTPU, "Create task for GTPV1U failed\n"); + return -1; + } + } + + # endif + */ + + if (gnb_nb > 0) { + LOG_I(NR_RRC,"Creating NR RRC gNB Task\n"); + + if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) { + LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n"); + return -1; + } + } + + return 0; +} + + +static void get_options(void) { + int tddflag, nonbiotflag; + uint32_t online_log_messages; + uint32_t glog_level, glog_verbosity; + uint32_t start_telnetsrv; + paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ; + paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ; + config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL); + + if (strlen(in_path) > 0) { + opt_type = OPT_PCAP; + opt_enabled=1; + printf("Enabling OPT for PCAP with the following file %s \n",in_path); + } + + if (strlen(in_ip) > 0) { + opt_enabled=1; + opt_type = OPT_WIRESHARK; + printf("Enabling OPT for wireshark for local interface"); + } + + config_process_cmdline( cmdline_logparams,sizeof(cmdline_logparams)/sizeof(paramdef_t),NULL); + + if(config_isparamset(cmdline_logparams,CMDLINE_ONLINELOG_IDX)) { + set_glog_onlinelog(online_log_messages); + } + + if(config_isparamset(cmdline_logparams,CMDLINE_GLOGLEVEL_IDX)) { + set_glog(glog_level); + } + + if (start_telnetsrv) { + load_module_shlib("telnetsrv",NULL,0,NULL); + } + +#if T_TRACER + paramdef_t cmdline_ttraceparams[] =CMDLINE_TTRACEPARAMS_DESC ; + config_process_cmdline( cmdline_ttraceparams,sizeof(cmdline_ttraceparams)/sizeof(paramdef_t),NULL); +#endif + + if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) { + memset((void *)&RC,0,sizeof(RC)); + /* Read RC configuration file */ + NRRCConfig(); + NB_gNB_INST = RC.nb_nr_inst; + NB_RU = RC.nb_RU; + printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %d\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU); + } + + if(parallel_config != NULL) set_parallel_conf(parallel_config); + + if(worker_config != NULL) set_worker_conf(worker_config); +} + + +#if T_TRACER + int T_nowait = 0; /* by default we wait for the tracer */ + int T_port = 2021; /* default port to listen to to wait for the tracer */ + int T_dont_fork = 0; /* default is to fork, see 'T_init' to understand */ +#endif + + + +void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { + int CC_id; + + for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + frame_parms[CC_id] = (NR_DL_FRAME_PARMS *) malloc(sizeof(NR_DL_FRAME_PARMS)); + config[CC_id] = (nfapi_nr_config_request_t *) malloc(sizeof(nfapi_nr_config_request_t)); + config[CC_id]->subframe_config.numerology_index_mu.value =1; + config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD + config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL + config[CC_id]->rf_config.dl_carrier_bandwidth.value = 106; + config[CC_id]->rf_config.ul_carrier_bandwidth.value = 106; + config[CC_id]->sch_config.physical_cell_id.value = 0; + ///dl frequency to be filled in + /* //Set some default values that may be overwritten while reading options + frame_parms[CC_id]->frame_type = FDD; + frame_parms[CC_id]->tdd_config = 3; + frame_parms[CC_id]->tdd_config_S = 0; + frame_parms[CC_id]->N_RB_DL = 100; + frame_parms[CC_id]->N_RB_UL = 100; + frame_parms[CC_id]->Ncp = NORMAL; + frame_parms[CC_id]->Ncp_UL = NORMAL; + frame_parms[CC_id]->Nid_cell = 0; + frame_parms[CC_id]->num_MBSFN_config = 0; + frame_parms[CC_id]->nb_antenna_ports_eNB = 1; + frame_parms[CC_id]->nb_antennas_tx = 1; + frame_parms[CC_id]->nb_antennas_rx = 1; + + frame_parms[CC_id]->nushift = 0; + + frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth; + frame_parms[CC_id]->phich_config_common.phich_duration = normal; + // UL RS Config + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0 + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0; + frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0; + + frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0; + frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0; + + // downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31. + // downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0]; + // downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0]; + // downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0]; + //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]); + frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0]; + */ + } +} + +/* +void init_openair0(void) { + + int card; + int i; + + for (card=0; card<MAX_CARDS; card++) { + + openair0_cfg[card].mmapped_dma=mmapped_dma; + openair0_cfg[card].configFilename = NULL; + + if(config[0]->rf_config.dl_carrier_bandwidth.value == 100) { + if (frame_parms[0]->threequarter_fs) { + openair0_cfg[card].sample_rate=23.04e6; + openair0_cfg[card].samples_per_frame = 230400; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } else { + openair0_cfg[card].sample_rate=30.72e6; + openair0_cfg[card].samples_per_frame = 307200; + openair0_cfg[card].tx_bw = 10e6; + openair0_cfg[card].rx_bw = 10e6; + } + } else if(config[0]->rf_config.dl_carrier_bandwidth.value == 50) { + openair0_cfg[card].sample_rate=15.36e6; + openair0_cfg[card].samples_per_frame = 153600; + openair0_cfg[card].tx_bw = 5e6; + openair0_cfg[card].rx_bw = 5e6; + } else if (config[0]->rf_config.dl_carrier_bandwidth.value == 25) { + openair0_cfg[card].sample_rate=7.68e6; + openair0_cfg[card].samples_per_frame = 76800; + openair0_cfg[card].tx_bw = 2.5e6; + openair0_cfg[card].rx_bw = 2.5e6; + } else if (config[0]->rf_config.dl_carrier_bandwidth.value == 6) { + openair0_cfg[card].sample_rate=1.92e6; + openair0_cfg[card].samples_per_frame = 19200; + openair0_cfg[card].tx_bw = 1.5e6; + openair0_cfg[card].rx_bw = 1.5e6; + } + + + if (config[0]->subframe_config.duplex_mode.value==TDD) + openair0_cfg[card].duplex_mode = duplex_mode_TDD; + else //FDD + openair0_cfg[card].duplex_mode = duplex_mode_FDD; + + printf("HW: Configuring card %d, nb_antennas_tx/rx %d/%d\n",card, + RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value, + RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value ); + openair0_cfg[card].Mod_id = 0; + + openair0_cfg[card].num_rb_dl=config[0]->rf_config.dl_carrier_bandwidth.value; + + openair0_cfg[card].clock_source = clock_source; + + + openair0_cfg[card].tx_num_channels=min(2,RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value ); + openair0_cfg[card].rx_num_channels=min(2,RC.gNB[0][0]->gNB_config.rf_config.tx_antenna_ports.value ); + + for (i=0; i<4; i++) { + + if (i<openair0_cfg[card].tx_num_channels) + openair0_cfg[card].tx_freq[i] = downlink_frequency[0][i] ; + else + openair0_cfg[card].tx_freq[i]=0.0; + + if (i<openair0_cfg[card].rx_num_channels) + openair0_cfg[card].rx_freq[i] =downlink_frequency[0][i] + uplink_frequency_offset[0][i] ; + else + openair0_cfg[card].rx_freq[i]=0.0; + + openair0_cfg[card].autocal[i] = 1; + openair0_cfg[card].tx_gain[i] = tx_gain[0][i]; + openair0_cfg[card].rx_gain[i] = RC.gNB[0][0]->rx_total_gain_dB; + + + openair0_cfg[card].configFilename = rf_config_file; + printf("Card %d, channel %d, Setting tx_gain %f, rx_gain %f, tx_freq %f, rx_freq %f\n", + card,i, openair0_cfg[card].tx_gain[i], + openair0_cfg[card].rx_gain[i], + openair0_cfg[card].tx_freq[i], + openair0_cfg[card].rx_freq[i]); + } + } // for loop on cards +} +*/ + +void wait_RUs(void) { + LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask); + // wait for all RUs to be configured over fronthaul + pthread_mutex_lock(&RC.ru_mutex); + + while (RC.ru_mask>0) { + pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex); + printf("RC.ru_mask:%02lx\n", RC.ru_mask); + } + + pthread_mutex_unlock(&RC.ru_mutex); + LOG_I(PHY,"RUs configured\n"); +} + +void wait_gNBs(void) { + int i,j; + int waiting=1; + + while (waiting==1) { + printf("Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_nr_sL1_inst %d)\n",RC.nb_nr_L1_inst); + usleep(50*1000); + waiting=0; + + for (i=0; i<RC.nb_nr_L1_inst; i++) { + printf("RC.nb_nr_L1_CC[%d]:%d\n", i, RC.nb_nr_L1_CC[i]); + + for (j=0; j<RC.nb_nr_L1_CC[i]; j++) { + if (RC.gNB[i][j]->configured==0) { + waiting=1; + break; + } + } + } + } + + printf("gNB L1 are configured\n"); +} + +#if defined(ENABLE_ITTI) +/* + * helper function to terminate a certain ITTI task + */ +void terminate_task(task_id_t task_id, module_id_t mod_id) { + LOG_I(ENB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id); + MessageDef *msg; + msg = itti_alloc_new_message (ENB_APP, TERMINATE_MESSAGE); + itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg); +} + +//extern void free_transport(PHY_VARS_gNB *); +extern void nr_phy_free_RU(RU_t *); + +int stop_L1L2(module_id_t gnb_id) { + LOG_W(ENB_APP, "stopping nr-softmodem\n"); + oai_exit = 1; + + if (!RC.ru) { + LOG_F(ENB_APP, "no RU configured\n"); + return -1; + } + + /* stop trx devices, multiple carrier currently not supported by RU */ + if (RC.ru[gnb_id]) { + if (RC.ru[gnb_id]->rfdevice.trx_stop_func) { + RC.ru[gnb_id]->rfdevice.trx_stop_func(&RC.ru[gnb_id]->rfdevice); + LOG_I(ENB_APP, "turned off RU rfdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off rfdevice due to missing trx_stop_func callback, proceding anyway!\n"); + } + + if (RC.ru[gnb_id]->ifdevice.trx_stop_func) { + RC.ru[gnb_id]->ifdevice.trx_stop_func(&RC.ru[gnb_id]->ifdevice); + LOG_I(ENB_APP, "turned off RU ifdevice\n"); + } else { + LOG_W(ENB_APP, "can not turn off ifdevice due to missing trx_stop_func callback, proceding anyway!\n"); + } + } else { + LOG_W(ENB_APP, "no RU found for index %d\n", gnb_id); + return -1; + } + + /* these tasks need to pick up new configuration */ + terminate_task(TASK_RRC_ENB, gnb_id); + terminate_task(TASK_L2L1, gnb_id); + LOG_I(ENB_APP, "calling kill_gNB_proc() for instance %d\n", gnb_id); + kill_gNB_proc(gnb_id); + LOG_I(ENB_APP, "calling kill_RU_proc() for instance %d\n", gnb_id); + kill_RU_proc(gnb_id); + oai_exit = 0; + + for (int cc_id = 0; cc_id < RC.nb_nr_CC[gnb_id]; cc_id++) { + //free_transport(RC.gNB[gnb_id][cc_id]); + phy_free_nr_gNB(RC.gNB[gnb_id][cc_id]); + } + + nr_phy_free_RU(RC.ru[gnb_id]); + free_lte_top(); + return 0; +} + +/* + * Restart the nr-softmodem after it has been soft-stopped with stop_L1L2() + */ +int restart_L1L2(module_id_t gnb_id) { + RU_t *ru = RC.ru[gnb_id]; + int cc_id; + MessageDef *msg_p = NULL; + LOG_W(ENB_APP, "restarting nr-softmodem\n"); + /* block threads */ + sync_var = -1; + + for (cc_id = 0; cc_id < RC.nb_nr_L1_CC[gnb_id]; cc_id++) { + RC.gNB[gnb_id][cc_id]->configured = 0; + } + + RC.ru_mask |= (1 << ru->idx); + /* copy the changed frame parameters to the RU */ + /* TODO this should be done for all RUs associated to this gNB */ + memcpy(&ru->nr_frame_parms, &RC.gNB[gnb_id][0]->frame_parms, sizeof(NR_DL_FRAME_PARMS)); + set_function_spec_param(RC.ru[gnb_id]); + LOG_I(ENB_APP, "attempting to create ITTI tasks\n"); + + if (itti_create_task (TASK_RRC_ENB, rrc_enb_task, NULL) < 0) { + LOG_E(RRC, "Create task for RRC eNB failed\n"); + return -1; + } else { + LOG_I(RRC, "Re-created task for RRC gNB successfully\n"); + } + + if (itti_create_task (TASK_L2L1, l2l1_task, NULL) < 0) { + LOG_E(PDCP, "Create task for L2L1 failed\n"); + return -1; + } else { + LOG_I(PDCP, "Re-created task for L2L1 successfully\n"); + } + + /* pass a reconfiguration request which will configure everything down to + * RC.eNB[i][j]->frame_parms, too */ + msg_p = itti_alloc_new_message(TASK_ENB_APP, RRC_CONFIGURATION_REQ); + RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[gnb_id]->configuration; + itti_send_msg_to_task(TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(gnb_id), msg_p); + /* TODO XForms might need to be restarted, but it is currently (09/02/18) + * broken, so we cannot test it */ + wait_gNBs(); + init_RU_proc(ru); + ru->rf_map.card = 0; + ru->rf_map.chain = 0; /* CC_id + chain_offset;*/ + wait_RUs(); + init_eNB_afterRU(); + printf("Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + return 0; +} +#endif + +static void wait_nfapi_init(char *thread_name) { + printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name); + pthread_mutex_lock( &nfapi_sync_mutex ); + + while (nfapi_sync_var<0) + pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex ); + + pthread_mutex_unlock(&nfapi_sync_mutex); + printf( "NFAPI: got sync (%s)\n", thread_name); +} + +int main( int argc, char **argv ) { + int i; +#if defined (XFORMS) + //void *status; +#endif + int CC_id; + int ru_id; +#if defined (XFORMS) + int ret; +#endif + start_background_system(); + + ///static configuration for NR at the moment + if ( load_configmodule(argc,argv) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + +#ifdef DEBUG_CONSOLE + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); +#endif + mode = normal_txrx; + memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS); + memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); + configure_linux(); + logInit(); + printf("Reading in command-line options\n"); + get_options (); + + if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) { + fprintf(stderr,"Getting configuration failed\n"); + exit(-1); + } + +#if T_TRACER + T_Config_Init(); +#endif + //randominit (0); + set_taus_seed (0); + printf("configuring for RAU/RRU\n"); + + if (opp_enabled ==1) { + reset_opp_meas(); + } + + cpuf=get_cpu_freq_GHz(); +#if defined(ENABLE_ITTI) + itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); + // initialize mscgen log after ITTI + MSC_INIT(MSC_E_UTRAN, THREAD_MAX+TASK_MAX); +#endif + + if (opt_type != OPT_NONE) { + if (init_opt(in_path, in_ip) == -1) + LOG_E(OPT,"failed to run OPT \n"); + } + +#ifdef PDCP_USE_NETLINK + netlink_init(); +#if defined(PDCP_USE_NETLINK_QUEUES) + pdcp_netlink_init(); +#endif +#endif +#if !defined(ENABLE_ITTI) + // to make a graceful exit when ctrl-c is pressed + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); +#endif +#ifndef PACKAGE_VERSION +# define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL" +#endif + LOG_I(HW, "Version: %s\n", PACKAGE_VERSION); +#if defined(ENABLE_ITTI) + + if (RC.nb_nr_inst > 0) { + // don't create if node doesn't connect to RRC/S1/GTP + AssertFatal(create_gNB_tasks(1) == 0,"cannot create ITTI tasks\n"); + } else { + printf("No ITTI, Initializing L1\n"); + RCconfig_L1(); + } + +#endif + /* Start the agent. If it is turned off in the configuration, it won't start */ + RCconfig_nr_flexran(); + + for (i = 0; i < RC.nb_nr_L1_inst; i++) { + flexran_agent_start(i); + } + + // init UE_PF_PO and mutex lock + pthread_mutex_init(&ue_pf_po_mutex, NULL); + memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs); + mlockall(MCL_CURRENT | MCL_FUTURE); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); +#ifdef XFORMS + int UE_id; + + if (do_forms==1) { + fl_initialize (&argc, argv, NULL, 0, 0); + form_stats_l2 = create_form_stats_form(); + fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + form_gnb[CC_id][UE_id] = create_phy_scope_gnb(); + sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id); + fl_show_form (form_gnb[CC_id][UE_id]->phy_scope_gnb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + + if (otg_enabled) { + fl_set_button(form_gnb[CC_id][UE_id]->button_0,1); + fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic ON"); + } else { + fl_set_button(form_gnb[CC_id][UE_id]->button_0,0); + fl_set_object_label(form_gnb[CC_id][UE_id]->button_0,"DL Traffic OFF"); + } + } // CC_id + } // UE_id + + threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW); + printf("Scope thread created, ret=%d\n",ret); + } + +#endif + usleep(10*1000); + + if (nfapi_mode) { + printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); + pthread_cond_init(&sync_cond,NULL); + pthread_mutex_init(&sync_mutex, NULL); + } + + const char *nfapi_mode_str = "<UNKNOWN>"; + + switch(nfapi_mode) { + case 0: + nfapi_mode_str = "MONOLITHIC"; + break; + + case 1: + nfapi_mode_str = "PNF"; + break; + + case 2: + nfapi_mode_str = "VNF"; + break; + + default: + nfapi_mode_str = "<UNKNOWN NFAPI MODE>"; + break; + } + + printf("NFAPI MODE:%s\n", nfapi_mode_str); + + if (nfapi_mode==2) // VNF + wait_nfapi_init("main?"); + + printf("START MAIN THREADS\n"); + // start the main threads + number_of_cards = 1; + printf("RC.nb_nr_L1_inst:%d\n", RC.nb_nr_L1_inst); + + if (RC.nb_nr_L1_inst > 0) { + printf("Initializing gNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync); + init_gNB(single_thread_flag,wait_for_sync); + } + + printf("wait_gNBs()\n"); + wait_gNBs(); + printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); + + if (RC.nb_RU >0) { + printf("Initializing RU threads\n"); + init_RU(rf_config_file); + + for (ru_id=0; ru_id<RC.nb_RU; ru_id++) { + RC.ru[ru_id]->rf_map.card=0; + RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset; + } + } + + config_sync_var=0; + + if (nfapi_mode==1) { // PNF + wait_nfapi_init("main?"); + } + + printf("wait RUs\n"); + wait_RUs(); + printf("ALL RUs READY!\n"); + printf("RC.nb_RU:%d\n", RC.nb_RU); + // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration) + printf("ALL RUs ready - init gNBs\n"); + + if (nfapi_mode != 1 && nfapi_mode != 2) { + printf("Not NFAPI mode - call init_eNB_afterRU()\n"); + init_eNB_afterRU(); + } else { + printf("NFAPI mode - DO NOT call init_gNB_afterRU()\n"); + } + + printf("ALL RUs ready - ALL gNBs ready\n"); + // connect the TX/RX buffers + printf("Sending sync to all threads\n"); + pthread_mutex_lock(&sync_mutex); + sync_var=0; + pthread_cond_broadcast(&sync_cond); + pthread_mutex_unlock(&sync_mutex); + printf("About to call end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + end_configmodule(); + printf("Called end_configmodule() from %s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); + // wait for end of program + printf("TYPE <CTRL-C> TO TERMINATE\n"); + //getchar(); +#if defined(ENABLE_ITTI) + printf("Entering ITTI signals handler\n"); + itti_wait_tasks_end(); + printf("Returned from ITTI signal handler\n"); + oai_exit=1; + printf("oai_exit=%d\n",oai_exit); +#else + + while (oai_exit==0) + sleep(1); + + printf("Terminating application - oai_exit=%d\n",oai_exit); +#endif + // stop threads +#ifdef XFORMS + /* + printf("waiting for XFORMS thread\n"); + + if (do_forms==1) { + pthread_join(forms_thread,&status); + fl_hide_form(form_stats->stats_form); + fl_free_form(form_stats->stats_form); + + fl_hide_form(form_stats_l2->stats_form); + fl_free_form(form_stats_l2->stats_form); + + for(UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + fl_hide_form(form_enb[CC_id][UE_id]->phy_scope_gNB); + fl_free_form(form_enb[CC_id][UE_id]->phy_scope_gNB); + } + } + } + */ +#endif + printf("stopping MODEM threads\n"); + // cleanup + stop_gNB(NB_gNB_INST); + stop_RU(NB_RU); + + /* release memory used by the RU/gNB threads (incomplete), after all + * threads have been stopped (they partially use the same memory) */ + for (int inst = 0; inst < NB_gNB_INST; inst++) { + for (int cc_id = 0; cc_id < RC.nb_nr_CC[inst]; cc_id++) { + //free_transport(RC.gNB[inst][cc_id]); + phy_free_nr_gNB(RC.gNB[inst][cc_id]); + } + } + + for (int inst = 0; inst < NB_RU; inst++) { + nr_phy_free_RU(RC.ru[inst]); + } + + free_lte_top(); + pthread_cond_destroy(&sync_cond); + pthread_mutex_destroy(&sync_mutex); + pthread_cond_destroy(&nfapi_sync_cond); + pthread_mutex_destroy(&nfapi_sync_mutex); + pthread_mutex_destroy(&ue_pf_po_mutex); + + // *** Handle per CC_id openair0 + + for(ru_id=0; ru_id<NB_RU; ru_id++) { + if (RC.ru[ru_id]->rfdevice.trx_end_func) + RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); + + if (RC.ru[ru_id]->ifdevice.trx_end_func) + RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); + } + + if (opt_enabled == 1) + terminate_opt(); + + logClean(); + printf("Bye.\n"); + return 0; +} diff --git a/executables/nr-softmodem.h b/executables/nr-softmodem.h new file mode 100644 index 0000000000000000000000000000000000000000..b01d92e6edd5ef10cb0a766a09df74a1e42fb42a --- /dev/null +++ b/executables/nr-softmodem.h @@ -0,0 +1,240 @@ +#ifndef NR_SOFTMODEM_H +#define NR_SOFTMODEM_H + +#define _GNU_SOURCE +#include <execinfo.h> +#include <fcntl.h> +#include <getopt.h> +#include <linux/sched.h> +#include <sched.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syscall.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#include <unistd.h> + +#include <sys/sysinfo.h> +#include "targets/ARCH/COMMON/common_lib.h" +#undef MALLOC +#include "assertions.h" +#include "msc.h" +#include "PHY/types.h" + +#include "flexran_agent.h" +#include "PHY/defs_gNB.h" + +#if defined(ENABLE_ITTI) + #if defined(ENABLE_USE_MME) + #include "s1ap_eNB.h" + #ifdef PDCP_USE_NETLINK + #include "SIMULATION/ETH_TRANSPORT/proto.h" + #endif + #endif +#endif + +/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */ +#define CONFIG_HLP_RFCFGF "Configuration file for front-end (e.g. LMS7002M)\n" +#define CONFIG_HLP_ULMAXE "set the eNodeB max ULSCH erros\n" +#define CONFIG_HLP_CALUER "set UE RX calibration\n" +#define CONFIG_HLP_CALUERM "" +#define CONFIG_HLP_CALUERB "" +#define CONFIG_HLP_DBGUEPR "UE run normal prach power ramping, but don't continue random-access\n" +#define CONFIG_HLP_CALPRACH "UE run normal prach with maximum power, but don't continue random-access\n" +#define CONFIG_HLP_NOL2CN "bypass L2 and upper layers\n" +#define CONFIG_HLP_UERXG "set UE RX gain\n" +#define CONFIG_HLP_UERXGOFF "external UE amplifier offset\n" +#define CONFIG_HLP_UETXG "set UE TX gain\n" +#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n" +#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n" +#define CONFIG_HLP_UESCAN "set UE to scan around carrier\n" +#define CONFIG_HLP_DUMPFRAME "dump UE received frame to rxsig_frame0.dat and exit\n" +#define CONFIG_HLP_DLSHIFT "dynamic shift for LLR compuation for TM3/4 (default 0)\n" +#define CONFIG_HLP_UELOOP "get softmodem (UE) to loop through memory instead of acquiring from HW\n" +#define CONFIG_HLP_PHYTST "test UE phy layer, mac disabled\n" +#define CONFIG_HLP_DMAMAP "sets flag for improved EXMIMO UE performance\n" +#define CONFIG_HLP_EXCCLK "tells hardware to use an external clock reference\n" +#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n" +#define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" +#define CONFIG_HLP_TADV "Set timing_advance\n" +#define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" +#define CONFIG_HLP_CHOFF "Channel id offset\n" +#define CONFIG_HLP_SOFTS "Enable soft scope and L1 and L2 stats (Xforms)\n" +#define CONFIG_HLP_EXMCAL "Calibrate the EXMIMO borad, available files: exmimo2_2arxg.lime exmimo2_2brxg.lime \n" +#define CONFIG_HLP_ITTIL "Generate ITTI analyzser logs (similar to wireshark logs but with more details)\n" +#define CONFIG_HLP_DLMCS "Set the maximum downlink MCS\n" +#define CONFIG_HLP_STMON "Enable processing timing measurement of lte softmodem on per subframe basis \n" +#define CONFIG_HLP_PRB "Set the PRB, valid values: 6, 25, 50, 100 \n" +#define CONFIG_HLP_MSLOTS "Skip the missed slots/subframes \n" +#define CONFIG_HLP_ULMCS "Set the maximum uplink MCS\n" +#define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n" +#define CONFIG_HLP_UE "Set the lte softmodem as a UE\n" +#define CONFIG_HLP_L2MONW "Enable L2 wireshark messages on localhost \n" +#define CONFIG_HLP_L2MONP "Enable L2 pcap messages on localhost \n" +#define CONFIG_HLP_VCD "Enable VCD (generated file will is named openair_dump_eNB.vcd, read it with target/RT/USER/eNB.gtkw\n" +#define CONFIG_HLP_TQFS "Apply three-quarter of sampling frequency, 23.04 Msps to reduce the data rate on USB/PCIe transfers (only valid for 20 MHz)\n" +#define CONFIG_HLP_TPORT "tracer port\n" +#define CONFIG_HLP_NOTWAIT "don't wait for tracer, start immediately\n" +#define CONFIG_HLP_TNOFORK "to ease debugging with gdb\n" +#define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" + +#define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n" +#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n" +#define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n" +#define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n" + +/***************************************************************************************************************************************/ +/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument + when calling config_get or config_getlist functions */ + + +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters defining UE running mode */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_UEMODEPARAMS_DESC { \ + {"calib-ue-rx", CONFIG_HLP_CALUER, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ + {"calib-ue-rx-med", CONFIG_HLP_CALUERM, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ + {"calib-ue-rx-byp", CONFIG_HLP_CALUERB, 0, iptr:&rx_input_level_dBm, defintval:0, TYPE_INT, 0}, \ + {"debug-ue-prach", CONFIG_HLP_DBGUEPR, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ + {"no-L2-connect", CONFIG_HLP_NOL2CN, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ + {"calib-prach-tx", CONFIG_HLP_CALPRACH, PARAMFLAG_BOOL, uptr:NULL, defuintval:1, TYPE_INT, 0}, \ + {"loop-memory", CONFIG_HLP_UELOOP, 0, strptr:&loopfile, defstrval:"iqs.in", TYPE_STRING,0}, \ + {"ue-dump-frame", CONFIG_HLP_DUMPFRAME, PARAMFLAG_BOOL, iptr:&dumpframe, defintval:0, TYPE_INT, 0}, \ + } +#define CMDLINE_CALIBUERX_IDX 0 +#define CMDLINE_CALIBUERXMED_IDX 1 +#define CMDLINE_CALIBUERXBYP_IDX 2 +#define CMDLINE_DEBUGUEPRACH_IDX 3 +#define CMDLINE_NOL2CONNECT_IDX 4 +#define CMDLINE_CALIBPRACHTX_IDX 5 +#define CMDLINE_MEMLOOP_IDX 6 +#define CMDLINE_DUMPMEMORY_IDX 7 +/*------------------------------------------------------------------------------------------------------------------------------------------*/ + + +#define DEFAULT_DLF 2680000000 + +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters common to eNodeB and UE */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_PARAMS_DESC { \ + {"rf-config-file", CONFIG_HLP_RFCFGF, 0, strptr:(char **)&rf_config_file, defstrval:NULL, TYPE_STRING, sizeof(rf_config_file)}, \ + {"ulsch-max-errors", CONFIG_HLP_ULMAXE, 0, uptr:&ULSCH_max_consecutive_errors, defuintval:0, TYPE_UINT, 0}, \ + {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, iptr:&phy_test, defintval:0, TYPE_INT, 0}, \ + {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, u8ptr:&usim_test, defintval:0, TYPE_UINT8, 0}, \ + {"mmapped-dma", CONFIG_HLP_DMAMAP, PARAMFLAG_BOOL, uptr:&mmapped_dma, defintval:0, TYPE_INT, 0}, \ + {"external-clock", CONFIG_HLP_EXCCLK, PARAMFLAG_BOOL, uptr:&clock_source, defintval:0, TYPE_INT, 0}, \ + {"wait-for-sync", NULL, PARAMFLAG_BOOL, iptr:&wait_for_sync, defintval:0, TYPE_INT, 0}, \ + {"single-thread-disable", CONFIG_HLP_NOSNGLT, PARAMFLAG_BOOL, iptr:&single_thread_flag, defintval:1, TYPE_INT, 0}, \ + {"A" , CONFIG_HLP_TADV, 0, uptr:&timing_advance, defintval:0, TYPE_UINT, 0}, \ + {"C" , CONFIG_HLP_DLF, 0, uptr:&(downlink_frequency[0][0]), defuintval:DEFAULT_DLF, TYPE_UINT, 0}, \ + {"a" , CONFIG_HLP_CHOFF, 0, iptr:&chain_offset, defintval:0, TYPE_INT, 0}, \ + {"d" , CONFIG_HLP_SOFTS, PARAMFLAG_BOOL, uptr:(uint32_t *)&do_forms, defintval:0, TYPE_INT8, 0}, \ + {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, i8ptr:&threequarter_fs, defintval:0, TYPE_INT8, 0}, \ + {"K" , CONFIG_HLP_ITTIL, PARAMFLAG_NOFREE, strptr:&itti_dump_file, defstrval:"/tmp/itti.dump", TYPE_STRING, 0}, \ + {"m" , CONFIG_HLP_DLMCS, 0, uptr:&target_dl_mcs, defintval:0, TYPE_UINT, 0}, \ + {"t" , CONFIG_HLP_ULMCS, 0, uptr:&target_ul_mcs, defintval:0, TYPE_UINT, 0}, \ + {"W" , CONFIG_HLP_L2MONW, 0, strptr:(char **)&in_ip, defstrval:"127.0.0.1", TYPE_STRING, sizeof(in_ip)}, \ + {"P" , CONFIG_HLP_L2MONP, 0, strptr:(char **)&in_path, defstrval:"/tmp/oai_opt.pcap", TYPE_STRING, sizeof(in_path)}, \ + {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, iptr:&opp_enabled, defintval:0, TYPE_INT, 0}, \ + {"S" , CONFIG_HLP_MSLOTS, PARAMFLAG_BOOL, u8ptr:&exit_missed_slots, defintval:1, TYPE_UINT8, 0}, \ + {"T" , CONFIG_HLP_TDD, PARAMFLAG_BOOL, iptr:&tddflag, defintval:0, TYPE_INT, 0}, {"numerology" , CONFIG_HLP_NUMEROLOGY, PARAMFLAG_BOOL, iptr:&numerology, defintval:0, TYPE_INT, 0}, \ + {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, iptr:&emulate_rf, defintval:0, TYPE_INT, 0}, \ + {"parallel-config", CONFIG_HLP_PARALLEL_CMD,0, strptr:(char **)¶llel_config, defstrval:NULL, TYPE_STRING, 0}, \ + {"worker-config", CONFIG_HLP_WORKER_CMD, 0, strptr:(char **)&worker_config, defstrval:NULL, TYPE_STRING, 0}, \ + {"nbiot-disable", CONFIG_HLP_DISABLNBIOT,PARAMFLAG_BOOL, iptr:&nonbiotflag, defintval:0, TYPE_INT, 0} \ + } + +#define CONFIG_HLP_FLOG "Enable online log \n" +#define CONFIG_HLP_LOGL "Set the global log level, valide options: (9:trace, 8/7:debug, 6:info, 4:warn, 3:error)\n" +#define CONFIG_HLP_LOGV "Set the global log verbosity \n" +#define CONFIG_HLP_TELN "Start embedded telnet server \n" +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +/* command line parameters for LOG utility */ +/* optname helpstr paramflags XXXptr defXXXval type numelt */ +/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CMDLINE_LOGPARAMS_DESC { \ + {"R" , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \ + {"g" , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \ + {"G" , CONFIG_HLP_LOGV, 0, uptr:&glog_verbosity, defintval:0, TYPE_UINT16, 0}, \ + {"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \ + } +#define CMDLINE_ONLINELOG_IDX 0 +#define CMDLINE_GLOGLEVEL_IDX 1 +#define CMDLINE_GLOGVERBO_IDX 2 +#define CMDLINE_STARTTELN_IDX 3 + + +typedef struct { + int *argc; + char **argv; +} scopeParms_t; + +extern int T_port; +extern int T_nowait; +extern int T_dont_fork; + + +/***************************************************************************************************************************************/ +/* */ +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; + + +extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; +extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; + +extern int rx_input_level_dBm; +extern uint8_t exit_missed_slots; +extern uint64_t num_missed_slots; // counter for the number of missed slots + +extern int oaisim_flag; +extern volatile int oai_exit; + +extern openair0_config_t openair0_cfg[MAX_CARDS]; +extern pthread_cond_t sync_cond; +extern pthread_mutex_t sync_mutex; +extern int sync_var; +extern int transmission_mode; +extern double cpuf; + +#if defined(ENABLE_ITTI) + extern volatile int start_gNB; +#endif + +#include "threads_t.h" +extern threads_t threads; + +// In nr-gnb.c +extern void init_gNB(int single_thread_flag,int wait_for_sync); +extern void stop_gNB(int); +extern void kill_gNB_proc(int inst); + +// In nr-ru.c +extern void init_RU(const char *); +extern void init_RU_proc(RU_t *ru); +extern void stop_RU(int nb_ru); +extern void kill_RU_proc(int inst); +extern void set_function_spec_param(RU_t *ru); + +extern void reset_opp_meas(void); +extern void print_opp_meas(void); + +extern void init_fep_thread(PHY_VARS_gNB *); + +void init_gNB_afterRU(void); + +extern int stop_L1L2(module_id_t gnb_id); +extern int restart_L1L2(module_id_t gnb_id); + +#endif + diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 19b462d7703f82510fe4c83a79260f2d9b967d58..bf0dc9809a21532bbf7047a7982229e208dcb16c 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -43,6 +43,7 @@ #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "common/utils/LOG/log.h" +#include "common/utils/system.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" @@ -123,7 +124,6 @@ extern double cpuf; #define FRAME_PERIOD 100000000ULL #define DAQ_PERIOD 66667ULL -#define FIFO_PRIORITY 40 typedef enum { pss=0, @@ -156,7 +156,7 @@ PHY_VARS_NR_UE *init_nr_ue_vars(NR_DL_FRAME_PARMS *frame_parms, */ typedef struct syncData_s { - UE_nr_rxtx_proc_t *proc; + UE_nr_rxtx_proc_t proc; PHY_VARS_NR_UE *UE; } syncData_t; @@ -239,7 +239,7 @@ static void UE_synch(void *arg) { case pbch: LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode); - if (nr_initial_sync( syncD->proc, UE, UE->mode ) == 0) { + if (nr_initial_sync( &syncD->proc, UE, UE->mode ) == 0) { freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_slot; LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n", @@ -375,7 +375,9 @@ void processSubframeRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) { #ifdef UE_SLOT_PARALLELISATION phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL ); #else + uint64_t a=rdtsc(); phy_procedures_nrUE_RX( UE, proc, 0, 1, UE->mode); + LOG_D(PHY,"phy_procedures_nrUE_RX: slot:%d, time %lu\n", proc->nr_tti_rx, (rdtsc()-a)/3500); // printf(">>> nr_ue_pdcch_procedures ended\n"); #endif } @@ -530,10 +532,12 @@ int computeSamplesShift(PHY_VARS_NR_UE *UE) { //LOG_I(PHY,"!!!adjusting +1 samples!!!\n"); return 1; } + return 0; } void *UE_thread(void *arg) { + //this thread should be over the processing thread to keep in real time PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg; // int tx_enabled = 0; openair0_timestamp timestamp; @@ -547,40 +551,45 @@ void *UE_thread(void *arg) { initNotifiedFIFO(&nf); int nbSlotProcessing=0; int thread_idx=0; - notifiedFIFO_elt_t *processingMsg[RX_NB_TH]; + notifiedFIFO_t freeBlocks; + initNotifiedFIFO_nothreadSafe(&freeBlocks); - for (int i=0; i<RX_NB_TH; i++) { - processingMsg[i]= newNotifiedFIFO_elt(sizeof(processingData_t), 0,&nf,UE_processing); - processingData_t *tmp=(processingData_t *)NotifiedFifoData(processingMsg[i]); - tmp->UE=UE; - } + for (int i=0; i<RX_NB_TH+1; i++) // RX_NB_TH working + 1 we are making to be pushed + pushNotifiedFIFO_nothreadSafe(&freeBlocks, + newNotifiedFIFO_elt(sizeof(processingData_t), 0,&nf,UE_processing)); bool syncRunning=false; - notifiedFIFO_elt_t *syncMsg=newNotifiedFIFO_elt(sizeof(syncData_t),0,&nf,UE_synch); - syncData_t *syncD=(syncData_t *)NotifiedFifoData(syncMsg); - syncD->UE=UE; - syncD->proc=&((processingData_t *)NotifiedFifoData(processingMsg[0]))->proc; const int nb_slot_frame = 10*UE->frame_parms.slots_per_subframe; - int absolute_slot, decoded_frame_rx=INT_MAX, trashed_frames=0; + int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0; while (!oai_exit) { - if (!syncD->UE->is_synchronized) { - if (syncRunning) { - notifiedFIFO_elt_t *res=tryPullTpool(&nf, Tpool); - - if (res) { - syncRunning=false; - } else { - trashFrame(UE, ×tamp); - trashed_frames++; - } + if (syncRunning) { + notifiedFIFO_elt_t *res=tryPullTpool(&nf, Tpool); + + if (res) { + syncRunning=false; + syncData_t *tmp=(syncData_t *)NotifiedFifoData(res); + // shift the frame index with all the frames we trashed meanwhile we perform the synch search + decoded_frame_rx=(tmp->proc.decoded_frame_rx+trashed_frames) % MAX_FRAME_NUMBER; + delNotifiedFIFO_elt(res); } else { - readFrame(UE, ×tamp); - pushTpool(Tpool, syncMsg); - trashed_frames=0; - syncRunning=true; + trashFrame(UE, ×tamp); + trashed_frames++; + continue; } + } + AssertFatal( !syncRunning, "At this point synchronisation can't be running\n"); + + if (!UE->is_synchronized) { + readFrame(UE, ×tamp); + notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(syncData_t),0,&nf,UE_synch); + syncData_t *syncMsg=(syncData_t *)NotifiedFifoData(Msg); + syncMsg->UE=UE; + memset(&syncMsg->proc, 0, sizeof(syncMsg->proc)); + pushTpool(Tpool, Msg); + trashed_frames=0; + syncRunning=true; continue; } @@ -598,29 +607,32 @@ void *UE_thread(void *arg) { UE->frame_parms.nb_antennas_rx),""); // we have the decoded frame index in the return of the synch process // and we shifted above to the first slot of next frame - // the synch thread proc context is hard linked to regular processing thread context, thread id = 0 - UE_nr_rxtx_proc_t *proc=&(((processingData_t *)NotifiedFifoData(processingMsg[0]))->proc); - // shift the frame index with all the frames we trashed meanwhile we perform the synch search - proc->decoded_frame_rx=(proc->decoded_frame_rx + trashed_frames) % MAX_FRAME_NUMBER; - decoded_frame_rx=proc->decoded_frame_rx; - // we do ++ first in the regular processing, so it will be 0; + decoded_frame_rx++; + // we do ++ first in the regular processing, so it will be beging of frame; absolute_slot=decoded_frame_rx*nb_slot_frame + nb_slot_frame -1; continue; } absolute_slot++; + // whatever means thread_idx + // Fix me: will be wrong when slot 1 is slow, as slot 2 finishes + // Slot 3 will overlap if RX_NB_TH is 2 + // this is general failure in UE !!! thread_idx = absolute_slot % RX_NB_TH; int slot_nr = absolute_slot % nb_slot_frame; - UE_nr_rxtx_proc_t *proc=&(((processingData_t *)NotifiedFifoData(processingMsg[thread_idx]))->proc); + notifiedFIFO_elt_t *msgToPush; + AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure"); + processingData_t *curMsg=(processingData_t *)NotifiedFifoData(msgToPush); + curMsg->UE=UE; // update thread index for received subframe - proc->nr_tti_rx= slot_nr; - UE->current_thread_id[slot_nr] = thread_idx; - proc->subframe_rx=table_sf_slot[slot_nr]; - proc->nr_tti_tx = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame; - proc->subframe_tx=proc->nr_tti_rx; - proc->frame_rx = ( absolute_slot/nb_slot_frame ) % MAX_FRAME_NUMBER; - proc->frame_tx = ( (absolute_slot + DURATION_RX_TO_TX) /nb_slot_frame ) % MAX_FRAME_NUMBER; - proc->decoded_frame_rx=-1; + curMsg->proc.nr_tti_rx= slot_nr; + curMsg->UE->current_thread_id[slot_nr] = thread_idx; + curMsg->proc.subframe_rx=table_sf_slot[slot_nr]; + curMsg->proc.nr_tti_tx = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame; + curMsg->proc.subframe_tx=curMsg->proc.nr_tti_rx; + curMsg->proc.frame_rx = ( absolute_slot/nb_slot_frame ) % MAX_FRAME_NUMBER; + curMsg->proc.frame_tx = ( (absolute_slot + DURATION_RX_TO_TX) /nb_slot_frame ) % MAX_FRAME_NUMBER; + curMsg->proc.decoded_frame_rx=-1; LOG_D(PHY,"Process slot %d thread Idx %d \n", slot_nr, thread_idx); for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) @@ -629,7 +641,7 @@ void *UE_thread(void *arg) { slot_nr*UE->frame_parms.samples_per_slot]; for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++) - txp[i] = (void *)&UE->common_vars.txdata[i][proc->nr_tti_tx*UE->frame_parms.samples_per_slot]; + txp[i] = (void *)&UE->common_vars.txdata[i][curMsg->proc.nr_tti_tx*UE->frame_parms.samples_per_slot]; int readBlockSize, writeBlockSize; @@ -678,41 +690,47 @@ void *UE_thread(void *arg) { LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols); } - proc->timestamp_tx = timestamp+ - (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot)- - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; + curMsg->proc.timestamp_tx = timestamp+ + (DURATION_RX_TO_TX*UE->frame_parms.samples_per_slot)- + UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; notifiedFIFO_elt_t *res; - if (getenv("RFSIMULATOR")) { - // FixMe: Wait previous thread is done, because race conditions seems too bad - // in case of actual RF board, the overlap between threads mitigate the issue - // We must receive one message, that proves the slot processing is done - while ((res=tryPullTpool(&nf, Tpool)) == NULL) - usleep(200); + while (nbSlotProcessing >= RX_NB_TH) { + if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) { + nbSlotProcessing--; + processingData_t *tmp=(processingData_t *)res->msgData; - nbSlotProcessing--; - processingData_t *tmp=(processingData_t *)res->msgData; + if (tmp->proc.decoded_frame_rx != -1) + decoded_frame_rx=tmp->proc.decoded_frame_rx; - if (tmp->proc.decoded_frame_rx != -1) - decoded_frame_rx=tmp->proc.decoded_frame_rx; + pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); + } + + usleep(200); } - while (nbSlotProcessing >= RX_NB_TH && (res=tryPullTpool(&nf, Tpool)) != NULL ) { + if ( decoded_frame_rx != curMsg->proc.frame_rx && + ((decoded_frame_rx+1) % MAX_FRAME_NUMBER) != curMsg->proc.frame_rx ) + LOG_D(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n", + decoded_frame_rx, curMsg->proc.frame_rx ); + + nbSlotProcessing++; + msgToPush->key=slot_nr; + pushTpool(Tpool, msgToPush); + + if (getenv("RFSIMULATOR")) { + // FixMe: Wait previous thread is done, because race conditions seems too bad + // in case of actual RF board, the overlap between threads mitigate the issue + // We must receive one message, that proves the slot processing is done + res=pullTpool(&nf, Tpool); nbSlotProcessing--; processingData_t *tmp=(processingData_t *)res->msgData; if (tmp->proc.decoded_frame_rx != -1) decoded_frame_rx=tmp->proc.decoded_frame_rx; - usleep(200); + pushNotifiedFIFO_nothreadSafe(&freeBlocks,res); } - - if ( decoded_frame_rx != proc->frame_rx && - ((decoded_frame_rx+1) % MAX_FRAME_NUMBER) != proc->frame_rx ) - LOG_D(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n", - decoded_frame_rx, proc->frame_rx); - - pushTpool(Tpool, processingMsg[thread_idx]); } // while !oai_exit return NULL; @@ -722,14 +740,6 @@ void init_UE(int nb_inst) { int inst; NR_UE_MAC_INST_t *mac_inst; pthread_t threads[nb_inst]; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); - pthread_attr_setschedpolicy(&attr, SCHED_RR); - struct sched_param sched; - sched.sched_priority = sched_get_priority_max(SCHED_RR)-1; - pthread_attr_setschedparam(&attr, &sched); for (inst=0; inst < nb_inst; inst++) { PHY_VARS_NR_UE *UE = PHY_vars_UE_g[inst][0]; @@ -738,25 +748,19 @@ void init_UE(int nb_inst) { nr_l2_init_ue(); mac_inst = get_mac_inst(inst); mac_inst->if_module = UE->if_inst; - // Initial bandwidth part configuration -- full carrier bandwidth mac_inst->initial_bwp_dl.bwp_id = 0; mac_inst->initial_bwp_dl.location = 0; mac_inst->initial_bwp_dl.scs = UE->frame_parms.subcarrier_spacing; mac_inst->initial_bwp_dl.N_RB = UE->frame_parms.N_RB_DL; mac_inst->initial_bwp_dl.cyclic_prefix = UE->frame_parms.Ncp; - mac_inst->initial_bwp_ul.bwp_id = 0; mac_inst->initial_bwp_ul.location = 0; mac_inst->initial_bwp_ul.scs = UE->frame_parms.subcarrier_spacing; mac_inst->initial_bwp_ul.N_RB = UE->frame_parms.N_RB_UL; mac_inst->initial_bwp_ul.cyclic_prefix = UE->frame_parms.Ncp; - LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]); - AssertFatal(0 == pthread_create(&threads[inst], - &attr, - UE_thread, - (void *)UE), ""); + threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX); } printf("UE threads created by %ld\n", gettid()); diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 24f8d4eb0d54fb97b42bae8fe88180ec6b0259b9..8300f10675946cb91d342a1d8e2280b8c052dff5 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -64,7 +64,6 @@ unsigned short config_frames[4] = {2,9,11,13}; #endif #include "intertask_interface.h" -#include "create_tasks.h" #include "PHY/INIT/phy_init.h" #include "system.h" @@ -98,11 +97,11 @@ extern FD_stats_form *create_form_stats_form( void ); //#include "stats.h" // current status is that every UE has a DL scope for a SINGLE eNB (eNB_id=0) // at eNB 0, an UL scope for every UE -FD_lte_phy_scope_ue *form_ue[NUMBER_OF_UE_MAX]; +FD_phy_scope_nrue *form_nrue[NUMBER_OF_UE_MAX]; //FD_lte_phy_scope_enb *form_enb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; //FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; char title[255]; -//unsigned char scope_enb_num_ue = 2; +unsigned char scope_enb_num_ue = 2; static pthread_t forms_thread; //xforms #endif //XFORMS #include <executables/nr-uesoftmodem.h> @@ -311,15 +310,10 @@ void reset_stats(FL_OBJECT *button, long arg) { } static void *scope_thread(void *arg) { - struct sched_param sched_param; - sched_param.sched_priority = sched_get_priority_min(SCHED_FIFO)+1; - sched_setscheduler(0, SCHED_FIFO,&sched_param); - printf("Scope thread has priority %d\n",sched_param.sched_priority); - //wait the modem is runnign sleep(5); while (!oai_exit) { - phy_scope_UE(form_ue[0], + phy_scope_nrUE(form_nrue[0], PHY_vars_UE_g[0][0], 0,0,1); usleep(100*1000); @@ -331,24 +325,16 @@ static void *scope_thread(void *arg) { void init_scope(void) { #ifdef XFORMS - int ret; int fl_argc=1; if (do_forms==1) { char *name="5G-UE-scope"; fl_initialize (&fl_argc, &name, NULL, 0, 0); int UE_id = 0; - form_ue[UE_id] = create_lte_phy_scope_ue(); + form_nrue[UE_id] = create_phy_scope_nrue(); sprintf (title, "NR DL SCOPE UE"); - fl_show_form (form_ue[UE_id]->lte_phy_scope_ue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); - fl_set_button(form_ue[UE_id]->button_0,0); - fl_set_object_label(form_ue[UE_id]->button_0, "IA Receiver OFF"); - ret = pthread_create(&forms_thread, NULL, scope_thread, NULL); - - if (ret == 0) - pthread_setname_np( forms_thread, "xforms" ); - - printf("Scope thread created, ret=%d\n",ret); + fl_show_form (form_nrue[UE_id]->phy_scope_nrue, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW); } #endif @@ -541,7 +527,6 @@ void set_default_frame_parms(NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { frame_parms[CC_id]->nb_antennas_tx = 1; frame_parms[CC_id]->nb_antennas_rx = 1; //frame_parms[CC_id]->nushift = 0; - // NR: Init to legacy LTE 20Mhz params frame_parms[CC_id]->numerology_index = 0; frame_parms[CC_id]->ttis_per_subframe = 1; @@ -685,7 +670,7 @@ int main( int argc, char **argv ) { set_taus_seed (0); tpool_t pool; Tpool = &pool; - char params[]="-1,-1,-1,-1"; + char params[]="-1,-1"; initTpool(params, Tpool, false); cpuf=get_cpu_freq_GHz(); itti_init(TASK_MAX, THREAD_MAX, MESSAGES_ID_MAX, tasks_info, messages_info); @@ -712,9 +697,7 @@ int main( int argc, char **argv ) { frame_parms[CC_id]->nb_antennas_rx = nb_antenna_rx; frame_parms[CC_id]->nb_antenna_ports_eNB = 1; //initial value overwritten by initial sync later LOG_I(PHY,"Set nb_rx_antenna %d , nb_tx_antenna %d \n",frame_parms[CC_id]->nb_antennas_rx, frame_parms[CC_id]->nb_antennas_tx); - get_band(downlink_frequency[CC_id][0], &frame_parms[CC_id]->eutra_band, &uplink_frequency_offset[CC_id][0], &frame_parms[CC_id]->frame_type); - } NB_UE_INST=1; @@ -766,6 +749,7 @@ int main( int argc, char **argv ) { // init UE_PF_PO and mutex lock pthread_mutex_init(&ue_pf_po_mutex, NULL); memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs); + configure_linux(); mlockall(MCL_CURRENT | MCL_FUTURE); init_scope(); number_of_cards = 1; diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 8bc07936f6b776741fb0b73cb9e60e7581fe5be4..078a8066c3c2c97088e00e2b3b8d624660eef0d4 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -236,7 +236,6 @@ extern double cpuf; extern int setup_ue_buffers(PHY_VARS_NR_UE **phy_vars_ue, openair0_config_t *openair0_cfg); extern void fill_ue_band_info(void); extern void init_UE(int); -extern void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char *name); extern void reset_opp_meas(void); extern void print_opp_meas(void); void *UE_thread(void *arg); diff --git a/executables/openairinterface5g_limits.h b/executables/openairinterface5g_limits.h new file mode 100644 index 0000000000000000000000000000000000000000..ca29078758aea5aa68c64dbe4fd135efbd94944f --- /dev/null +++ b/executables/openairinterface5g_limits.h @@ -0,0 +1,89 @@ +#ifndef OPENAIRINTERFACE5G_LIMITS_H_ +#define OPENAIRINTERFACE5G_LIMITS_H_ + +#if 1 /*defined(CBMIMO1) || defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_LMSSDR) || defined(OAI_ADRV9371_ZC706)*/ + #define NUMBER_OF_eNB_MAX 1 + #define NUMBER_OF_gNB_MAX 1 + #define NUMBER_OF_RU_MAX 2 + #define NUMBER_OF_NR_RU_MAX 2 + #ifndef PHYSIM + #ifndef UE_EXPANSION + #define NUMBER_OF_UE_MAX 4 + #define NUMBER_OF_NR_UE_MAX 4 + #define NUMBER_OF_CONNECTED_eNB_MAX 1 + #define NUMBER_OF_CONNECTED_gNB_MAX 1 + #else + #define NUMBER_OF_UE_MAX 256 + #define NUMBER_OF_NR_UE_MAX 256 + #define NUMBER_OF_CONNECTED_eNB_MAX 1 + #define NUMBER_OF_CONNECTED_gNB_MAX 1 + #endif + #else + #define NUMBER_OF_UE_MAX 1 + #define NUMBER_OF_NR_UE_MAX 1 + #define NUMBER_OF_CONNECTED_eNB_MAX 1 + #define NUMBER_OF_CONNECTED_gNB_MAX 1 + #endif +#else + #define NUMBER_OF_eNB_MAX 7 + #define NUMBER_OF_gNB_MAX 7 + #define NUMBER_OF_RU_MAX 32 + #define NUMBER_OF_NR_RU_MAX 32 + #ifndef UE_EXPANSION + #define NUMBER_OF_UE_MAX 20 + #define NUMBER_OF_NR_UE_MAX 20 + #define NUMBER_OF_CONNECTED_eNB_MAX 3 + #define NUMBER_OF_CONNECTED_gNB_MAX 3 + #else + #define NUMBER_OF_UE_MAX 256 + #define NUMBER_OF_NR_UE_MAX 256 + #define NUMBER_OF_CONNECTED_eNB_MAX 1 + #define NUMBER_OF_CONNECTED_gNB_MAX 1 + #endif + #if defined(STANDALONE) && STANDALONE==1 + #undef NUMBER_OF_eNB_MAX + #undef NUMBER_OF_gNB_MAX + + #undef NUMBER_OF_UE_MAX + #undef NUMBER_OF_NR_UE_MAX + + #undef NUMBER_OF_RU_MAX + #undef NUMBER_OF_NR_RU_MAX + + #define NUMBER_OF_eNB_MAX 3 + #define NUMBER_OF_gNB_MAX 3 + + #define NUMBER_OF_UE_MAX 3 + #define NUMBER_OF_NR_UE_MAX 3 + + #define NUMBER_OF_RU_MAX 3 + #define NUMBER_OF_NR_RU_MAX 3 + #endif + #if defined(LARGE_SCALE) && LARGE_SCALE + #undef NUMBER_OF_eNB_MAX + #undef NUMBER_OF_gNB_MAX + + #undef NUMBER_OF_UE_MAX + #undef NUMBER_OF_NR_UE_MAX + + #undef NUMBER_OF_CONNECTED_eNB_MAX + #undef NUMBER_OF_CONNECTED_gNB_MAX + + #undef NUMBER_OF_RU_MAX + #undef NUMBER_OF_NR_RU_MAX + + #define NUMBER_OF_eNB_MAX 2 + #define NUMBER_OF_gNB_MAX 2 + + #define NUMBER_OF_UE_MAX 120 + #define NUMBER_OF_NR_UE_MAX 120 + + #define NUMBER_OF_RU_MAX 16 + #define NUMBER_OF_NR_RU_MAX 16 + + #define NUMBER_OF_CONNECTED_eNB_MAX 1 // to save some memory + #define NUMBER_OF_CONNECTED_gNB_MAX 1 + #endif +#endif + +#endif /* OPENAIRINTERFACE5G_LIMITS_H_ */ diff --git a/executables/stats.h b/executables/stats.h new file mode 100644 index 0000000000000000000000000000000000000000..6c847a2860662e1aec2afebb751a4a122a342b6e --- /dev/null +++ b/executables/stats.h @@ -0,0 +1,46 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/* Header file generated by fdesign on Thu Aug 28 12:13:51 2014 */ + +#ifndef FD_stats_form_h_ +#define FD_stats_form_h_ + +#include <forms.h> + +/* Callbacks, globals and object handlers */ + +extern void reset_stats( FL_OBJECT *, long ); + +/* Forms and Objects */ + +typedef struct { + FL_FORM *stats_form; + void *vdata; + char *cdata; + long ldata; + FL_OBJECT *stats_text; + FL_OBJECT *stats_button; +} FD_stats_form; + +extern FD_stats_form *create_form_stats_form( void ); + +#endif /* FD_stats_form_h_ */ diff --git a/executables/threads_t.h b/executables/threads_t.h new file mode 100644 index 0000000000000000000000000000000000000000..0671f409883256b4db50e1c9c68778a1840ae5ef --- /dev/null +++ b/executables/threads_t.h @@ -0,0 +1,21 @@ +#ifndef _THREADS_T_H_ +#define _THREADS_T_H_ + +typedef struct threads_s { + int main; + int sync; + int one; + int two; + int three; + int slot1_proc_one; + int slot1_proc_two; + int slot1_proc_three; + //int dlsch_td_one; + //int dlsch_td_two; + //int dlsch_td_three; + //int dlsch_td1_one; + //int dlsch_td1_two; + //int dlsch_td1_three; +} threads_t; + +#endif /* _THREADS_T_H_ */ diff --git a/openair1/PHY/CODING/nr_polar_init.c b/openair1/PHY/CODING/nr_polar_init.c index f158d4430300be8c533326c3b20edc288845c70c..efc78d91fd96c2922391ab8b7ce95e2609314d0d 100644 --- a/openair1/PHY/CODING/nr_polar_init.c +++ b/openair1/PHY/CODING/nr_polar_init.c @@ -53,7 +53,7 @@ static void nr_polar_init(t_nrPolar_params * *polarParams, // printf("currentPtr %p (polarParams %p)\n",currentPtr,polarParams); //Else, initialize and add node to the end of the linked list. - t_nrPolar_params *newPolarInitNode = malloc(sizeof(t_nrPolar_params)); + t_nrPolar_params *newPolarInitNode = calloc(sizeof(t_nrPolar_params),1); if (newPolarInitNode != NULL) { newPolarInitNode->idx = (messageType * messageLength * aggregation_prime); diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index f5f6ca152381eb86f9f422167f028a88fbe192f6..63aeba0480288d3b4711ff1f4d4d50deef8083ce 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -369,7 +369,7 @@ void phy_config_harq_ue(module_id_t Mod_id, for (num_of_threads=0;num_of_threads<RX_NB_TH_MAX;num_of_threads++) for (num_of_code_words=0;num_of_code_words<NR_MAX_NB_CODEWORDS;num_of_code_words++) - phy_vars_ue->ulsch[eNB_id][num_of_threads][num_of_code_words]->Mlimit = max_harq_tx; + phy_vars_ue->ulsch[num_of_threads][eNB_id][num_of_code_words]->Mlimit = max_harq_tx; } extern uint16_t beta_cqi[16]; diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c index b44a04eb742488b2dc599ba83997619987630d41..0709cca69b409dcf94ac102535993d6cf8c1ce73 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c @@ -41,7 +41,6 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/log.h" #include <syscall.h> -#include "targets/RT/USER/rt_wrapper.h" //#define DEBUG_DLSCH_CODING //#define DEBUG_DLSCH_FREE 1 @@ -329,11 +328,6 @@ int dlsch_encoding_2threads0(te_params *tep) { extern int oai_exit; void *te_thread(void *param) { - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - thread_top_init("te_thread",1,200000,250000,500000); - pthread_setname_np( pthread_self(),"te processing"); - LOG_I(PHY,"thread te created id=%ld\n", syscall(__NR_gettid)); te_params *tep = (te_params *)param; //wait_sync("te_thread"); diff --git a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c index 1dcbec06640dbd34d638159d9eb2fb01fc958e37..6d16c5fb0e78379bdbed21c20724f2c85ea78466 100644 --- a/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c +++ b/openair1/PHY/LTE_TRANSPORT/ulsch_decoding.c @@ -42,7 +42,6 @@ #include "common/utils/LOG/vcd_signal_dumper.h" //#define DEBUG_ULSCH_DECODING -#include "targets/RT/USER/rt_wrapper.h" #include "transport_proto.h" extern WORKER_CONF_t get_thread_worker_conf(void); @@ -356,9 +355,7 @@ extern int oai_exit; void *td_thread(void *param) { PHY_VARS_eNB *eNB = ((td_params *)param)->eNB; L1_proc_t *proc = &eNB->proc; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - thread_top_init("td_thread",1,200000,250000,500000); + pthread_setname_np( pthread_self(),"td processing"); LOG_I(PHY,"thread td created id=%ld\n", syscall(__NR_gettid)); //wait_sync("td_thread"); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index a83242efaf48aa90ab1b13c9b70cd456c1f63b7b..4bdc30540d7e784425294ea1bc1ad8024874587a 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -36,6 +36,7 @@ //#include "extern.h" #include "PHY/sse_intrin.h" #include "T.h" +#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" #ifndef USER_MODE #define NOCYGWIN_STATIC static @@ -84,6 +85,20 @@ unsigned char offset_mumimo_llr_drange[29][3]={{8,8,8},{7,7,7},{7,7,7},{7,7,7},{ extern void print_shorts(char *s,int16_t *x); +static void nr_dlsch_dual_stream_correlation_core(int **dl_ch_estimates_ext, + int **dl_ch_estimates_ext_i, + int **dl_ch_rho_ext, + unsigned char n_tx, + unsigned char n_rx, + unsigned char output_shift, + int length, + int start_point); + +static void nr_dlsch_layer_demapping(int16_t **llr_cw, + uint8_t Nl, + uint8_t mod_order, + uint16_t length, + int16_t **llr_layers); int nr_rx_pdsch(PHY_VARS_NR_UE *ue, PDSCH_t type, @@ -112,7 +127,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, uint8_t slot = 0; #endif - unsigned char aatx,aarx; + unsigned char aatx=0,aarx=0; unsigned short nb_rb = 0, round; int avgs = 0;// rb; @@ -993,10 +1008,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, if (rx_type==rx_IC_dual_stream) { nr_dlsch_layer_demapping(pdsch_vars[eNB_id]->llr, - dlsch[0]->harq_processes[harq_pid]->Nl, - dlsch[0]->harq_processes[harq_pid]->Qm, - dlsch[0]->harq_processes[harq_pid]->G, - pdsch_vars[eNB_id]->layer_llr); + dlsch[0]->harq_processes[harq_pid]->Nl, + dlsch[0]->harq_processes[harq_pid]->Qm, + dlsch[0]->harq_processes[harq_pid]->G, + pdsch_vars[eNB_id]->layer_llr); } #if UE_TIMING_TRACE @@ -2048,7 +2063,7 @@ void nr_dlsch_channel_level_median(int **dl_ch_estimates_ext, } -void nr_dlsch_dual_stream_correlation_core(int **dl_ch_estimates_ext, +static void nr_dlsch_dual_stream_correlation_core(int **dl_ch_estimates_ext, int **dl_ch_estimates_ext_i, int **dl_ch_rho_ext, unsigned char n_tx, @@ -2156,7 +2171,7 @@ void nr_dlsch_detection_mrc_core(int **rxdataF_comp, __m128i *rxdataF_comp128_0, *rxdataF_comp128_1, *rxdataF_comp128_2, *rxdataF_comp128_3; __m128i *dl_ch_mag128_0, *dl_ch_mag128_1, *dl_ch_mag128_2, *dl_ch_mag128_3; __m128i *dl_ch_mag128_0b, *dl_ch_mag128_1b, *dl_ch_mag128_2b, *dl_ch_mag128_3b; - __m128i *rho128_0, *rho128_1, *rho128_2, *rho128_3; + __m128i *rho128_0, *rho128_1, *rho128_2=NULL, *rho128_3=NULL; __m128i *rho128_i0, *rho128_i1, *rho128_i2, *rho128_i3; int length_mod4 = 0; int length2; @@ -2458,7 +2473,7 @@ unsigned short nr_dlsch_extract_rbs_dual(int **rxdataF, int prb,nb_rb=0; unsigned short k; int i,j,aarx; - int32_t *dl_ch0,*dl_ch0p,*dl_ch0_ext,*dl_ch1,*dl_ch1p,*dl_ch1_ext,*rxF,*rxF_ext; + int32_t *dl_ch0=NULL,*dl_ch0p=NULL,*dl_ch0_ext=NULL,*dl_ch1=NULL,*dl_ch1p=NULL,*dl_ch1_ext=NULL,*rxF=NULL,*rxF_ext=NULL; k = frame_parms->first_carrier_offset + 516; //0 @@ -2533,11 +2548,12 @@ unsigned short nr_dlsch_extract_rbs_dual(int **rxdataF, return(nb_rb/frame_parms->nb_antennas_rx); } -void nr_dlsch_layer_demapping(int16_t **llr_cw, - uint8_t Nl, - uint8_t mod_order, - uint16_t length, - int16_t **llr_layers) { + +static void nr_dlsch_layer_demapping(int16_t **llr_cw, + uint8_t Nl, + uint8_t mod_order, + uint16_t length, + int16_t **llr_layers) { switch (Nl) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 4885c1c3e45e3eb6f38f433f1b583744e654d602..e7af6323277b05b70cc85096775e69e869b8c9ef 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -1803,21 +1803,6 @@ int nr_extract_dci_info(PHY_VARS_NR_UE *ue, uint16_t n_RB_DLBWP, uint16_t crc_scrambled_values[TOTAL_NBR_SCRAMBLED_VALUES]); -void nr_dlsch_dual_stream_correlation_core(int **dl_ch_estimates_ext, - int **dl_ch_estimates_ext_i, - int **dl_ch_rho_ext, - unsigned char n_tx, - unsigned char n_rx, - unsigned char output_shift, - int length, - int start_point); - -void nr_dlsch_layer_demapping(int16_t **llr_cw, - uint8_t Nl, - uint8_t mod_order, - uint16_t length, - int16_t **llr_layers); - /**@}*/ #endif diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index d1f1d1bea8ee07ceb10a99240d74cf58898bec34..f8c0aad3f29bf6b19bff029a7d53fdd672823c18 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -35,8 +35,6 @@ float tput_time_ue[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}}; float tput_ue[NUMBER_OF_UE_MAX][TPUT_WINDOW_LENGTH] = {{0}}; float tput_ue_max[NUMBER_OF_UE_MAX] = {0}; -extern int64_t *pss_corr_ue[3]; - static void ia_receiver_on_off( FL_OBJECT *button, long arg) { @@ -66,14 +64,14 @@ static void dl_traffic_on_off( FL_OBJECT *button, long arg) } } -FD_lte_phy_scope_enb *create_lte_phy_scope_enb( void ) +FD_phy_scope_gnb *create_phy_scope_gnb( void ) { FL_OBJECT *obj; - FD_lte_phy_scope_enb *fdui = fl_malloc( sizeof *fdui ); + FD_phy_scope_gnb *fdui = fl_malloc( sizeof *fdui ); // Define form - fdui->lte_phy_scope_enb = fl_bgn_form( FL_NO_BOX, 800, 800 ); + fdui->phy_scope_gnb = fl_bgn_form( FL_NO_BOX, 800, 800 ); // This the whole UI box obj = fl_add_box( FL_BORDER_BOX, 0, 0, 800, 800, "" ); @@ -146,19 +144,17 @@ FD_lte_phy_scope_enb *create_lte_phy_scope_enb( void ) fl_set_object_callback(fdui->button_0, dl_traffic_on_off, 0 ); fl_end_form( ); - fdui->lte_phy_scope_enb->fdui = fdui; + fdui->phy_scope_gnb->fdui = fdui; return fdui; } -/* -void phy_scope_eNB(FD_lte_phy_scope_enb *form, - PHY_VARS_eNB *phy_vars_enb, +void phy_scope_gNB(FD_phy_scope_gnb *form, + PHY_VARS_gNB *phy_vars_gnb, int UE_id) { - int eNB_id = 0; int i,i2,arx,atx,ind,k; - LTE_DL_FRAME_PARMS *frame_parms = &phy_vars_enb->frame_parms; + NR_DL_FRAME_PARMS *frame_parms = &phy_vars_gnb->frame_parms; int nsymb_ce = 12*frame_parms->N_RB_UL*frame_parms->symbols_per_tti; uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; uint8_t nb_antennas_tx = 1; // frame_parms->nb_antennas_tx; // in LTE Rel. 8 and 9 only a single transmit antenna is assumed at the UE @@ -180,16 +176,18 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, float time[FRAME_LENGTH_COMPLEX_SAMPLES]; float time2[2048]; float freq[nsymb_ce*nb_antennas_rx*nb_antennas_tx]; - int frame = phy_vars_enb->proc.proc_rxtx[0].frame_tx; - uint32_t total_dlsch_bitrate = phy_vars_enb->total_dlsch_bitrate; + uint32_t total_dlsch_bitrate = phy_vars_gnb->total_dlsch_bitrate; int coded_bits_per_codeword = 0; uint8_t harq_pid; // in TDD config 3 it is sf-2, i.e., can be 0,1,2 int Qm = 2; + if (!RC.nrmac[0]->UE_list.active[UE_id]) + return; + // choose max MCS to compute coded_bits_per_codeword - if (phy_vars_enb->ulsch[UE_id]!=NULL) { + if (phy_vars_gnb->ulsch[UE_id][0]!=NULL) { for (harq_pid=0; harq_pid<3; harq_pid++) { - Qm = cmax(phy_vars_enb->ulsch[UE_id]->harq_processes[harq_pid]->Qm,Qm); + //Qm = cmax(phy_vars_gnb->ulsch[UE_id][0]->harq_processes->Qm,Qm); } } @@ -199,15 +197,15 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, llr = (float*) calloc(coded_bits_per_codeword,sizeof(float)); // init to zero bit = malloc(coded_bits_per_codeword*sizeof(float)); - rxsig_t = (int16_t**) phy_vars_enb->common_vars.rxdata[eNB_id]; - //chest_t = (int16_t**) phy_vars_enb->pusch_vars[UE_id]->drs_ch_estimates_time[eNB_id]; - chest_t = (int16_t**) phy_vars_enb->srs_vars[UE_id].srs_ch_estimates[eNB_id]; - chest_f = (int16_t**) phy_vars_enb->pusch_vars[UE_id]->drs_ch_estimates[eNB_id]; - pusch_llr = (int16_t*) phy_vars_enb->pusch_vars[UE_id]->llr; - pusch_comp = (int32_t*) phy_vars_enb->pusch_vars[UE_id]->rxdataF_comp[0]; - pucch1_comp = (int32_t*) phy_vars_enb->pucch1_stats[UE_id]; - pucch1_thres = (int32_t*) phy_vars_enb->pucch1_stats_thres[UE_id]; - pucch1ab_comp = (int32_t*) phy_vars_enb->pucch1ab_stats[UE_id]; + rxsig_t = (int16_t**) phy_vars_gnb->common_vars.rxdata; + //chest_t = (int16_t**) phy_vars_gnb->pusch_vars[UE_id]->drs_ch_estimates_time[eNB_id]; + chest_t = (int16_t**) phy_vars_gnb->srs_vars[UE_id].srs_ch_estimates; + chest_f = (int16_t**) phy_vars_gnb->pusch_vars[UE_id]->drs_ch_estimates; + pusch_llr = (int16_t*) phy_vars_gnb->pusch_vars[UE_id]->llr; + pusch_comp = (int32_t*) phy_vars_gnb->pusch_vars[UE_id]->rxdataF_comp; + pucch1_comp = (int32_t*) phy_vars_gnb->pucch1_stats[UE_id]; + pucch1_thres = (int32_t*) phy_vars_gnb->pucch1_stats_thres[UE_id]; + pucch1ab_comp = (int32_t*) phy_vars_gnb->pucch1ab_stats[UE_id]; // Received signal in time domain of receive antenna 0 if (rxsig_t != NULL) { @@ -363,7 +361,7 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, memmove( tput_time_enb[UE_id], &tput_time_enb[UE_id][1], (TPUT_WINDOW_LENGTH-1)*sizeof(float) ); memmove( tput_enb[UE_id], &tput_enb[UE_id][1], (TPUT_WINDOW_LENGTH-1)*sizeof(float) ); - tput_time_enb[UE_id][TPUT_WINDOW_LENGTH-1] = (float) frame; + tput_time_enb[UE_id][TPUT_WINDOW_LENGTH-1] = (float) 0; tput_enb[UE_id][TPUT_WINDOW_LENGTH-1] = ((float) total_dlsch_bitrate)/1000.0; fl_set_xyplot_data(form->pusch_tput,tput_time_enb[UE_id],tput_enb[UE_id],TPUT_WINDOW_LENGTH,"","",""); @@ -377,16 +375,15 @@ void phy_scope_eNB(FD_lte_phy_scope_enb *form, free(bit); free(chest_f_abs); } -*/ -FD_lte_phy_scope_ue *create_lte_phy_scope_ue( void ) +FD_phy_scope_nrue *create_phy_scope_nrue( void ) { FL_OBJECT *obj; - FD_lte_phy_scope_ue *fdui = fl_malloc( sizeof *fdui ); + FD_phy_scope_nrue *fdui = fl_malloc( sizeof *fdui ); // Define form - fdui->lte_phy_scope_ue = fl_bgn_form( FL_NO_BOX, 800, 900 ); + fdui->phy_scope_nrue = fl_bgn_form( FL_NO_BOX, 800, 900 ); // This the whole UI box obj = fl_add_box( FL_BORDER_BOX, 0, 0, 800, 900, "" ); @@ -477,12 +474,12 @@ FD_lte_phy_scope_ue *create_lte_phy_scope_ue( void ) fl_hide_object(fdui->button_0); fl_end_form( ); - fdui->lte_phy_scope_ue->fdui = fdui; + fdui->phy_scope_nrue->fdui = fdui; return fdui; } -void phy_scope_UE(FD_lte_phy_scope_ue *form, +void phy_scope_nrUE(FD_phy_scope_nrue *form, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id, @@ -629,6 +626,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, if (phy_vars_ue->is_synchronized==0) { for (ind=0;ind<3;ind++) { + /* if (pss_corr_ue[ind]) { for (i=0; i<samples_per_frame; i++) { corr[i] = (float) pss_corr_ue[ind][i]; @@ -642,6 +640,7 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, overlay = 1; } + */ } } else { @@ -843,3 +842,91 @@ void phy_scope_UE(FD_lte_phy_scope_ue *form, free(chest_t_abs); */ } + +typedef struct { + FL_FORM *stats_form; + void *vdata; + char *cdata; + long ldata; + FL_OBJECT *stats_text; + FL_OBJECT *stats_button; +} FD_stats_form; + +void reset_stats_gNB(FL_OBJECT *button, long arg) { + PHY_VARS_gNB *phy_vars_gNB = RC.gNB[0][0]; + + for (int i=0; i<NUMBER_OF_UE_MAX; i++) { + for (int k=0; k<8; k++) { //harq_processes + /* for (j=0; j<phy_vars_gNB->dlsch[i][0]->Mlimit; j++) { + phy_vars_gNB->UE_stats[i].dlsch_NAK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_ACK[k][j]=0; + phy_vars_gNB->UE_stats[i].dlsch_trials[k][j]=0; + }*/ + phy_vars_gNB->UE_stats[i].dlsch_l2_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_errors[k]=0; + phy_vars_gNB->UE_stats[i].ulsch_consecutive_errors=0; + phy_vars_gNB->UE_stats[i].dlsch_sliding_cnt=0; + phy_vars_gNB->UE_stats[i].dlsch_NAK_round0=0; + phy_vars_gNB->UE_stats[i].dlsch_mcs_offset=0; + } + } +} + +static FD_phy_scope_gnb *form_gnb[MAX_NUM_CCs][NUMBER_OF_UE_MAX]; +static void *scope_thread(void *arg) { + int ue_cnt=0; + while (!oai_exit) { + ue_cnt=0; + + for(int UE_id=0; UE_id<NUMBER_OF_UE_MAX; UE_id++) { + for(int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + if ((ue_cnt<scope_enb_num_ue)) + //this function needs to be written + phy_scope_gNB(form_gnb[CC_id][ue_cnt], RC.gNB[0][CC_id], UE_id); + ue_cnt++; + } + } + sleep(1); + } + return NULL; +} + +FD_stats_form * create_form_stats_form( void ) { + FL_OBJECT *obj; + FD_stats_form *fdui = fl_malloc( sizeof *fdui ); + fdui->vdata = fdui->cdata = NULL; + fdui->ldata = 0; + fdui->stats_form = fl_bgn_form( FL_NO_BOX, 1115, 900 ); + obj = fl_add_box( FL_UP_BOX, 0, 0, 1115, 900, "" ); + //fdui->stats_text = obj = fl_add_text( FL_NORMAL_TEXT, 60, 50, 1000, 810, "test" ); + //fl_set_object_lsize( obj, FL_TINY_SIZE ); + fdui->stats_text = obj = fl_add_browser( FL_NORMAL_BROWSER, 60, 50, 1000, 810, "test" ); + fl_set_browser_fontsize(obj,FL_TINY_SIZE); + fdui->stats_button = obj = fl_add_button( FL_PUSH_BUTTON, 60, 10, 130, 30, "Reset Stats" ); + fl_set_object_lalign( obj, FL_ALIGN_CENTER ); + fl_set_object_color( obj, FL_GREEN, FL_GREEN); + fl_end_form( ); + fdui->stats_form->fdui = fdui; + return fdui; +} + +void startScope(scopeParms_t * p) { + FD_stats_form *form_stats=NULL,*form_stats_l2=NULL; + char title[255]; + fl_initialize (p->argc, p->argv, NULL, 0, 0); + form_stats_l2 = create_form_stats_form(); + fl_show_form (form_stats_l2->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "l2 stats"); + form_stats = create_form_stats_form(); + fl_show_form (form_stats->stats_form, FL_PLACE_HOTSPOT, FL_FULLBORDER, "stats"); + + for(int UE_id=0; UE_id<scope_enb_num_ue; UE_id++) { + for(int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { + form_gnb[CC_id][UE_id] = create_phy_scope_gnb(); + sprintf (title, "LTE UL SCOPE eNB for CC_id %d, UE %d",CC_id,UE_id); + fl_show_form (form_gnb[CC_id][UE_id]->phy_scope_gnb, FL_PLACE_HOTSPOT, FL_FULLBORDER, title); + } // CC_id + } // UE_id + + pthread_t forms_thread; + threadCreate(&forms_thread, scope_thread, NULL, "scope", -1, OAI_PRIORITY_RT_LOW); +} diff --git a/openair1/PHY/TOOLS/nr_phy_scope.h b/openair1/PHY/TOOLS/nr_phy_scope.h index eaf42bafab1439d52ff1dadecf942a086f9a4606..9c161988a168376b6aa4c9391ceb6ad691f6aa4f 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_scope.h @@ -21,19 +21,24 @@ /* Header file generated by fdesign on Tue Nov 13 09:42:50 2012 */ -#ifndef FD_lte_scope_h_ -#define FD_lte_scope_h_ - +#ifndef FD_nr_scope_h_ +#define FD_nr_scope_h_ +#include <simple_executable.h> +#include <common/utils/system.h> +#include <openairinterface5g_limits.h> +#include <openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h> +#include "common/ran_context.h" +#include <openair1/PHY/defs_gNB.h> +#include <nr-softmodem.h> #include <forms.h> -//#include "PHY/defs_eNB.h" -//#include "PHY/defs_UE.h" +#include "PHY/defs_gNB.h" +//#include "PHY/defs_nrUE.h" //#include "PHY/impl_defs_top.h" #include "PHY/defs_nr_UE.h" - /* Forms and Objects */ typedef struct { - FL_FORM * lte_phy_scope_enb; + FL_FORM * phy_scope_gnb; FL_OBJECT * rxsig_t; FL_OBJECT * chest_f; FL_OBJECT * chest_t; @@ -43,10 +48,10 @@ typedef struct { FL_OBJECT * pusch_llr; FL_OBJECT * pusch_tput; FL_OBJECT * button_0; -} FD_lte_phy_scope_enb; +} FD_phy_scope_gnb; typedef struct { - FL_FORM * lte_phy_scope_ue; + FL_FORM * phy_scope_nrue; FL_OBJECT * rxsig_t; FL_OBJECT * chest_f; FL_OBJECT * chest_t; @@ -61,24 +66,22 @@ typedef struct { FL_OBJECT * pdsch_tput; FL_OBJECT * button_0; -} FD_lte_phy_scope_ue; +} FD_phy_scope_nrue; -FD_lte_phy_scope_enb * create_lte_phy_scope_enb( void ); -FD_lte_phy_scope_ue * create_lte_phy_scope_ue( void ); +extern unsigned char scope_enb_num_ue; +FD_phy_scope_gnb * create_phy_scope_gnb( void ); +FD_phy_scope_nrue * create_phy_scope_nrue( void ); -/* -void phy_scope_eNB(FD_lte_phy_scope_enb *form, - PHY_VARS_gNB *phy_vars_enb, + +void phy_scope_gNB(FD_phy_scope_gnb *form, + PHY_VARS_gNB *phy_vars_gnb, int UE_id); -*/ -void phy_scope_UE(FD_lte_phy_scope_ue *form, + +void phy_scope_nrUE(FD_phy_scope_nrue *form, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id, uint8_t subframe); - - - - -#endif /* FD_lte_scope_h_ */ +extern RAN_CONTEXT_t RC; +#endif diff --git a/openair1/PHY/defs_L1_NB_IoT.h b/openair1/PHY/defs_L1_NB_IoT.h index 6945bbe10614033a8462709cc73acd7563a584b9..3ab8409c35f779b9df23ac97edd125430602c2f6 100644 --- a/openair1/PHY/defs_L1_NB_IoT.h +++ b/openair1/PHY/defs_L1_NB_IoT.h @@ -139,7 +139,7 @@ static inline void* malloc16_clear( size_t size ) #include <pthread.h> #include "targets/ARCH/COMMON/common_lib.h" -#include "targets/COMMON/openairinterface5g_limits.h" +#include "openairinterface5g_limits.h" #define NUM_DCI_MAX_NB_IoT 32 diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 3e9ecc10bbc623ba179ec434d137b3b2f6d2585d..48981ddf1a6777c174e4b890f06fc162bfb014db 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -70,7 +70,7 @@ #include "TOOLS/tools_defs.h" -#include "targets/COMMON/openairinterface5g_limits.h" +#include "openairinterface5g_limits.h" #include "common/utils/LOG/log.h" #include "types.h" diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index cb4b635cb1f692d8811f07bf2b61f36f58068775..4d2ff771d0932a2416ba6fd13c6ec806f7d3562d 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -497,8 +497,8 @@ typedef struct RRU_config_s { #include <pthread.h> -#include "targets/ARCH/COMMON/common_lib.h" -#include "targets/COMMON/openairinterface5g_limits.h" +#include "common_lib.h" +#include "openairinterface5g_limits.h" #define NUMBER_OF_SUBBANDS_MAX 13 diff --git a/openair1/PHY/phy_extern.h b/openair1/PHY/phy_extern.h index 623a4bb0c615309274e9b8f13047939692051a4b..9baf8bf21d6bbbdfe1c9f8f0fcc4878f8ed5aee2 100644 --- a/openair1/PHY/phy_extern.h +++ b/openair1/PHY/phy_extern.h @@ -40,16 +40,9 @@ extern int number_of_cards; extern short conjugate[8],conjugate2[8]; -#ifndef OCP_FRAMEWORK -//extern PHY_VARS_eNB ***PHY_vars_eNB_g; -extern RAN_CONTEXT_t RC; -extern LTE_DL_FRAME_PARMS *lte_frame_parms_g; -#else -#define MAX_UE 10 -#define MAX_eNB 20 -extern PHY_VARS_eNB * PHY_vars_eNB_g[MAX_eNB][MAX_NUM_CCs]; -#endif + +extern RAN_CONTEXT_t RC; extern short primary_synch0[144]; extern short primary_synch1[144]; diff --git a/openair1/PHY/phy_extern_nr_ue.h b/openair1/PHY/phy_extern_nr_ue.h index 66dbd82fc49ba24dc86ccf34596035477565368d..70fbd21ffa8d9bad1bf4f57e17c16f320b99b87a 100644 --- a/openair1/PHY/phy_extern_nr_ue.h +++ b/openair1/PHY/phy_extern_nr_ue.h @@ -38,15 +38,7 @@ extern short conjugate[8],conjugate2[8]; extern int number_of_cards; -#ifndef OCP_FRAMEWORK extern PHY_VARS_NR_UE ***PHY_vars_UE_g; -extern NR_DL_FRAME_PARMS *lte_frame_parms_g; -#else -#define MAX_UE 10 -#define MAX_eNB 20 - -extern PHY_VARS_NR_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]; -#endif extern short primary_synch0[144]; extern short primary_synch1[144]; diff --git a/openair1/PHY/phy_extern_ue.h b/openair1/PHY/phy_extern_ue.h index 596686f261a31a64aa93572a2956e03aa55be465..6fd53ac15caf4839cd01de1ece1a8de112684e4a 100644 --- a/openair1/PHY/phy_extern_ue.h +++ b/openair1/PHY/phy_extern_ue.h @@ -38,15 +38,8 @@ extern int number_of_cards; extern short conjugate[8],conjugate2[8]; -#ifndef OCP_FRAMEWORK -extern PHY_VARS_UE ***PHY_vars_UE_g; -extern LTE_DL_FRAME_PARMS *lte_frame_parms_g; -#else -#define MAX_UE 10 -#define MAX_eNB 20 -extern PHY_VARS_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]; -#endif +extern PHY_VARS_UE ***PHY_vars_UE_g; extern short primary_synch0[144]; extern short primary_synch1[144]; diff --git a/openair1/PHY/phy_vars.h b/openair1/PHY/phy_vars.h index 897d826ae2c288e52afe2e3ebd943542da64fe83..4cf029e968c3ba9ca7f346b76cb10f039c97cd68 100644 --- a/openair1/PHY/phy_vars.h +++ b/openair1/PHY/phy_vars.h @@ -41,19 +41,10 @@ int16_t *primary_synch2_time; #include "PHY/LTE_TRANSPORT/transport_vars.h" #include "PHY/MODULATION/modulation_vars.h" -//PHY_VARS *PHY_vars; -#ifndef OCP_FRAMEWORK -PHY_VARS_UE ***PHY_vars_UE_g; -RAN_CONTEXT_t RC; -//PHY_VARS_eNB ***PHY_vars_eNB_g; -//PHY_VARS_RN **PHY_vars_RN_g; -LTE_DL_FRAME_PARMS *lte_frame_parms_g; -#else -PHY_VARS_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]={NULL}; -PHY_VARS_eNB * PHY_vars_eNB_g[MAX_eNB][MAX_NUM_CCs]={NULL}; -#endif +PHY_VARS_UE ***PHY_vars_UE_g; +RAN_CONTEXT_t RC; unsigned short rev[2048],rev_times4[8192],rev_half[1024]; unsigned short rev256[256],rev512[512],rev1024[1024],rev4096[4096],rev2048[2048],rev8192[8192]; diff --git a/openair1/PHY/phy_vars_nr_ue.h b/openair1/PHY/phy_vars_nr_ue.h index 0e7e4f79d1a46863223469436acd500c03b185dd..77163c0bc0a3928937d3fffdb72bea8fca00553a 100644 --- a/openair1/PHY/phy_vars_nr_ue.h +++ b/openair1/PHY/phy_vars_nr_ue.h @@ -40,16 +40,10 @@ int16_t *primary_synch2_time; //#include "PHY/CODING/coding_vars.h" -//PHY_VARS *PHY_vars; -#ifndef OCP_FRAMEWORK -PHY_VARS_NR_UE ***PHY_vars_UE_g; -PHY_VARS_eNB ***PHY_vars_eNB_g; -NR_DL_FRAME_PARMS *lte_frame_parms_g; -#else -PHY_VARS_NR_UE * PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]={NULL}; -#endif +PHY_VARS_NR_UE ***PHY_vars_UE_g; +PHY_VARS_eNB ***PHY_vars_eNB_g; unsigned short rev[2048],rev_times4[8192],rev_half[1024]; unsigned short rev256[256],rev512[512],rev1024[1024],rev4096[4096],rev2048[2048],rev8192[8192]; diff --git a/openair1/PHY/phy_vars_ue.h b/openair1/PHY/phy_vars_ue.h index 6cd7957884c76ace6f54fe6125bd2b942088380a..1021253ba1638bfa79b00cf439c5cb6a3f8b01f6 100644 --- a/openair1/PHY/phy_vars_ue.h +++ b/openair1/PHY/phy_vars_ue.h @@ -37,17 +37,7 @@ int16_t *primary_synch0_time; int16_t *primary_synch1_time; int16_t *primary_synch2_time; - - -//PHY_VARS *PHY_vars; -#ifndef OCP_FRAMEWORK PHY_VARS_UE ***PHY_vars_UE_g; -LTE_DL_FRAME_PARMS *lte_frame_parms_g; -#else -PHY_VARS_UE *PHY_vars_UE_g[MAX_UE][MAX_NUM_CCs]= {NULL}; - -#endif - unsigned short rev[2048],rev_times4[8192],rev_half[1024]; unsigned short rev256[256],rev512[512],rev1024[1024],rev4096[4096],rev2048[2048],rev8192[8192]; diff --git a/openair1/PHY/thread_NR_UE.h b/openair1/PHY/thread_NR_UE.h index cba7a5ae41729f04859cb8fc197d64a05c15c6e2..c5db3e14d76089bc0391c38c3457670010fb83bf 100644 --- a/openair1/PHY/thread_NR_UE.h +++ b/openair1/PHY/thread_NR_UE.h @@ -32,8 +32,6 @@ typedef struct { //pthread_t pthread_slot0_dl_processing; pthread_t pthread_slot1_dl_processing; /// pthread attributes for fep_slot1 processing thread - // pthread_attr_t attr_slot0_dl_processing; - pthread_attr_t attr_slot1_dl_processing; /// condition variable for UE fep_slot1 thread; //pthread_cond_t cond_slot0_dl_processing; pthread_cond_t cond_slot1_dl_processing; @@ -46,8 +44,6 @@ typedef struct { //pthread_t pthread_slot0_dl_processing; pthread_t pthread_dlsch_td; /// pthread attributes for fep_slot1 processing thread - // pthread_attr_t attr_slot0_dl_processing; - pthread_attr_t attr_dlsch_td; /// condition variable for UE fep_slot1 thread; //pthread_cond_t cond_slot0_dl_processing; pthread_cond_t cond_dlsch_td; diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c index 3b3b9336d4e482481680636e0b5fe936e6c42fd6..ba90220d0bb434e72edbf82aa63d4f50a690debf 100644 --- a/openair1/SCHED/phy_procedures_lte_eNb.c +++ b/openair1/SCHED/phy_procedures_lte_eNb.c @@ -38,6 +38,7 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "fapi_l1.h" #include "common/utils/LOG/log.h" +#include <common/utils/system.h> #include "common/utils/LOG/vcd_signal_dumper.h" #include "assertions.h" @@ -1351,12 +1352,11 @@ extern void *td_thread (void *); void init_td_thread(PHY_VARS_eNB *eNB) { L1_proc_t *proc = &eNB->proc; proc->tdp.eNB = eNB; - proc->instance_cnt_td = -1; - pthread_attr_init( &proc->attr_td); - pthread_mutex_init( &proc->mutex_td, NULL); - pthread_cond_init( &proc->cond_td, NULL); - pthread_create(&proc->pthread_td, &proc->attr_td, td_thread, (void *)&proc->tdp); + proc->instance_cnt_td = -1; + + threadCreate(&proc->pthread_td, td_thread, (void*)&proc->tdp, "TD", -1, OAI_PRIORITY_RT); } + void kill_td_thread(PHY_VARS_eNB *eNB) { L1_proc_t *proc = &eNB->proc; proc->instance_cnt_td = 0; @@ -1368,20 +1368,23 @@ void kill_td_thread(PHY_VARS_eNB *eNB) { extern void *te_thread (void *); -void init_te_thread(PHY_VARS_eNB *eNB) { +void init_te_thread(PHY_VARS_eNB *eNB) +{ L1_proc_t *proc = &eNB->proc; for(int i=0; i<3 ; i++) { proc->tep[i].eNB = eNB; - proc->tep[i].instance_cnt_te = -1; - pthread_mutex_init( &proc->tep[i].mutex_te, NULL); - pthread_cond_init( &proc->tep[i].cond_te, NULL); - pthread_attr_init( &proc->tep[i].attr_te); + proc->tep[i].instance_cnt_te = -1; + LOG_I(PHY,"Creating te_thread %d\n",i); - pthread_create(&proc->tep[i].pthread_te, &proc->tep[i].attr_te, te_thread, (void *)&proc->tep[i]); + char txt[128]; + sprintf(txt,"TE_%d", i); + threadCreate(&proc->tep[i].pthread_te, te_thread, (void*)&proc->tep[i], txt, -1, OAI_PRIORITY_RT); } } -void kill_te_thread(PHY_VARS_eNB *eNB) { + +void kill_te_thread(PHY_VARS_eNB *eNB) +{ L1_proc_t *proc = &eNB->proc; for(int i=0; i<3 ; i++) { @@ -1393,7 +1396,11 @@ void kill_te_thread(PHY_VARS_eNB *eNB) { } } -void fill_rx_indication(PHY_VARS_eNB *eNB,int UE_id,int frame,int subframe) { +void fill_rx_indication(PHY_VARS_eNB *eNB, + int UE_id, + int frame, + int subframe) +{ nfapi_rx_indication_pdu_t *pdu; int timing_advance_update; int sync_pos; diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index f30f09859cbd665dbe6296deb59a2a5d61f8d92a..2724567f4b9a94a2a36fb3c2076df72cd1166cd5 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -44,12 +44,11 @@ #include "assertions.h" +#include "common/utils/system.h" #include "msc.h" #include <time.h> -#include "targets/RT/USER/rt_wrapper.h" - extern int oai_exit; @@ -131,17 +130,8 @@ static void *feptx_thread(void *param) { RU_t *ru = (RU_t *)param; RU_proc_t *proc = &ru->proc; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - - thread_top_init("feptx_thread",1,85000,120000,500000); - pthread_setname_np( pthread_self(),"feptx processing"); - LOG_I(PHY,"thread feptx created id=%ld\n", syscall(__NR_gettid)); - //CPU_SET(6, &cpuset); - //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - //wait_sync("feptx_thread"); - + LOG_I(PHY,"thread feptx created \n"); while (!oai_exit) { @@ -162,8 +152,6 @@ static void *feptx_thread(void *param) { }*/ } - - return(NULL); } @@ -438,16 +426,6 @@ static void *fep_thread(void *param) { RU_t *ru = (RU_t *)param; RU_proc_t *proc = &ru->proc; - thread_top_init("fep_thread",1,100000,120000,5000000); - pthread_setname_np( pthread_self(),"fep processing"); - LOG_I(PHY,"thread fep created id=%ld\n", syscall(__NR_gettid)); - - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - //CPU_SET(2, &cpuset); - //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - //wait_sync("fep_thread"); - while (!oai_exit) { if (wait_on_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread")<0) break; @@ -483,7 +461,7 @@ void init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx) { pthread_mutex_init( &proc->mutex_feptx, NULL); pthread_cond_init( &proc->cond_feptx, NULL); - pthread_create(&proc->pthread_feptx, attr_feptx, feptx_thread, (void*)ru); + threadCreate(&proc->pthread_feptx, feptx_thread, (void*)ru, "feptx", -1, OAI_PRIORITY_RT); } @@ -497,7 +475,7 @@ void init_fep_thread(RU_t *ru,pthread_attr_t *attr_fep) { pthread_mutex_init( &proc->mutex_fep, NULL); pthread_cond_init( &proc->cond_fep, NULL); - pthread_create(&proc->pthread_fep, attr_fep, fep_thread, (void*)ru); + threadCreate(&proc->pthread_fep, fep_thread, (void*)ru, "fep", -1, OAI_PRIORITY_RT); } diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 65dfb64734b683f8a1b6eef5df3ef9c40a0451ef..653e9632b5072e7d8cbb82b272182e711f4fbd5e 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -41,6 +41,7 @@ #include "LAYER2/MAC/mac_extern.h" #include "LAYER2/MAC/mac.h" #include "common/utils/LOG/log.h" +#include "common/utils/system.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "T.h" @@ -49,9 +50,6 @@ #include "msc.h" #include <time.h> - -#include "targets/RT/USER/rt_wrapper.h" - // RU OFDM Modulator gNodeB extern openair0_config_t openair0_cfg[MAX_CARDS]; @@ -179,7 +177,6 @@ static void *nr_feptx_thread(void *param) { RU_t *ru = (RU_t *)param; RU_proc_t *proc = &ru->proc; - thread_top_init("nr_feptx_thread",0,870000,1000000,1000000); while (!oai_exit) { @@ -196,7 +193,7 @@ static void *nr_feptx_thread(void *param) { return(NULL); } -void nr_init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx) { +void nr_init_feptx_thread(RU_t *ru) { RU_proc_t *proc = &ru->proc; @@ -205,7 +202,7 @@ void nr_init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx) { pthread_mutex_init( &proc->mutex_feptx, NULL); pthread_cond_init( &proc->cond_feptx, NULL); - pthread_create(&proc->pthread_feptx, attr_feptx, nr_feptx_thread, (void*)ru); + threadCreate(&proc->pthread_feptx, nr_feptx_thread, (void*)ru, "feptx", -1, OAI_PRIORITY_RT); } diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index a120b8c1402ff187525fb8328a045c139dbf8b50..7c5a5d0146301793a7e8ca4bc8d4297e6336ff2f 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -38,10 +38,13 @@ nr_slot_t nr_slot_select (nfapi_nr_config_request_t *cfg, unsigned char slot); void nr_set_ssb_first_subcarrier(nfapi_nr_config_request_t *cfg, NR_DL_FRAME_PARMS *fp); void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, gNB_L1_rxtx_proc_t *proc, int do_meas); void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame, int slot); -void nr_init_feptx_thread(RU_t *ru,pthread_attr_t *attr_feptx); +void nr_init_feptx_thread(RU_t *ru); void nr_feptx_ofdm(RU_t *ru); void nr_feptx_ofdm_2thread(RU_t *ru); void nr_feptx0(RU_t *ru,int first_symbol, int num_symbols); +void fep_full(RU_t *ru); +void feptx_prec(RU_t *ru); +int nr_phy_init_RU(RU_t *ru); void nr_configure_css_dci_initial(nfapi_nr_dl_config_pdcch_parameters_rel15_t* pdcch_params, nr_scs_e scs_common, diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index f26468fb0315d2884aa7a366102723dd011bda9d..0a087d5b8b9c4efdc8365286ff4ebc896bf05309 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -3155,36 +3155,42 @@ int nr_ue_pdcch_procedures(uint8_t eNB_id, /* * This is the NR part */ - - if ((dci_alloc_rx[i].format == format0_0)) - if ((dci_alloc_rx[i].format == format1_0) && - (dci_alloc_rx[i].rnti != crc_scrambled_values[_P_RNTI_]) && - (dci_alloc_rx[i].rnti != crc_scrambled_values[_SI_RNTI_]) && - (dci_alloc_rx[i].rnti != crc_scrambled_values[_RA_RNTI_])) ue->dlsch_received[eNB_id]++; - - if ((dci_alloc_rx[i].rnti == crc_scrambled_values[_SI_RNTI_]) && (dci_alloc_rx[i].format == format1_0)) ue->dlsch_SI_received[eNB_id]++; - if ((dci_alloc_rx[i].rnti == crc_scrambled_values[_P_RNTI_]) && (dci_alloc_rx[i].format == format1_0)) ue->dlsch_p_received[eNB_id]++; - if ((dci_alloc_rx[i].rnti == crc_scrambled_values[_RA_RNTI_]) && (dci_alloc_rx[i].format == format1_0)) ue->dlsch_ra_received[eNB_id]++; - if ((dci_alloc_rx[i].format == format2_0)){ - } - if ((dci_alloc_rx[i].format == format2_1)){ - } - if ((dci_alloc_rx[i].format == format2_2)){ - } - if ((dci_alloc_rx[i].format == format2_3)){ - } - if ((dci_alloc_rx[i].format == format0_1)){ // This format not implemented at a first time. FIXME - } - if ((dci_alloc_rx[i].format == format1_1)){ // This format not implemented at a first time. FIXME - } - - + if ((dci_alloc_rx[i].format == format0_0)){ + } + + if (dci_alloc_rx[i].format == format1_0) { + if ((dci_alloc_rx[i].rnti != crc_scrambled_values[_P_RNTI_]) && + (dci_alloc_rx[i].rnti != crc_scrambled_values[_SI_RNTI_]) && + (dci_alloc_rx[i].rnti != crc_scrambled_values[_RA_RNTI_])) + ue->dlsch_received[eNB_id]++; + + if (dci_alloc_rx[i].rnti == crc_scrambled_values[_SI_RNTI_]) + ue->dlsch_SI_received[eNB_id]++; + if (dci_alloc_rx[i].rnti == crc_scrambled_values[_P_RNTI_]) + ue->dlsch_p_received[eNB_id]++; + if (dci_alloc_rx[i].rnti == crc_scrambled_values[_RA_RNTI_]) + ue->dlsch_ra_received[eNB_id]++; + } + + if ((dci_alloc_rx[i].format == format2_0)){ + } + if ((dci_alloc_rx[i].format == format2_1)){ + } + if ((dci_alloc_rx[i].format == format2_2)){ + } + if ((dci_alloc_rx[i].format == format2_3)){ + } + if ((dci_alloc_rx[i].format == format0_1)){ // This format not implemented at a first time. FIXME + } + if ((dci_alloc_rx[i].format == format1_1)){ // This format not implemented at a first time. FIXME + } + uint8_t status=0; - + LOG_D(PHY,"<-NR_PDCCH_PHY_PROCEDURES_UE (nr_ue_pdcch_procedures)-> dci_format=%d, rnti=%d, dci_length=%d, dci_pdu[0]=0x%lx, dci_pdu[1]=0x%lx\n",dci_alloc_rx[i].format,dci_alloc_rx[i].rnti,dci_alloc_rx[i].dci_length,dci_alloc_rx[i].dci_pdu[0],dci_alloc_rx[i].dci_pdu[1]); - + memset(&ue->dci_ind.dci_list[i].dci,0,sizeof(fapi_nr_dci_pdu_rel15_t)); - + ue->dci_ind.dci_list[i].rnti = dci_alloc_rx[i].rnti; ue->dci_ind.dci_list[i].dci_format = dci_alloc_rx[i].format; ue->dci_ind.dci_list[i].n_CCE = dci_alloc_rx[i].firstCCE; @@ -3203,15 +3209,15 @@ int nr_ue_pdcch_procedures(uint8_t eNB_id, pdcch_vars2->n_RB_BWP[nb_searchspace_active], pdcch_vars2->n_RB_BWP[nb_searchspace_active], crc_scrambled_values); - + if(status == 0) { LOG_W(PHY,"<-NR_PDCCH_PHY_PROCEDURES_UE (nr_ue_pdcch_procedures)-> bad DCI %d !!! \n",dci_alloc_rx[i].format); return(-1); } LOG_D(PHY,"<-NR_PDCCH_PHY_PROCEDURES_UE (nr_ue_pdcch_procedures)-> Ending function nr_extract_dci_info()\n"); - - /* + + /* nr_generate_ue_ul_dlsch_params_from_dci(ue, eNB_id, frame_rx, diff --git a/openair2/ENB_APP/RRC_config_tools.h b/openair2/ENB_APP/RRC_config_tools.h index a44da1f90c5d93a706f7a29e575cedd2989645ff..488441ff59f8cd68c258645cb5a9cddc3eeec9bd 100644 --- a/openair2/ENB_APP/RRC_config_tools.h +++ b/openair2/ENB_APP/RRC_config_tools.h @@ -30,7 +30,7 @@ #define RRC_CONFIG_TOOLS_H_ #define KHz (1000UL) -#define MHz (1000 * KHz) +#define MHz (1000*KHz) typedef struct eutra_band_s { int16_t band; diff --git a/openair2/ENB_APP/enb_app.c b/openair2/ENB_APP/enb_app.c index 0580f0eb52cffe0fffd2cecab1234059b76cfdae..2d5134e0d9e3dc35360a774e779ef1545aa82a1d 100644 --- a/openair2/ENB_APP/enb_app.c +++ b/openair2/ENB_APP/enb_app.c @@ -51,14 +51,11 @@ #include "openair1/PHY/INIT/phy_init.h" extern unsigned char NB_eNB_INST; +#include <nr-softmodem.h> extern RAN_CONTEXT_t RC; # define ENB_REGISTER_RETRY_DELAY 10 -#include "targets/RT/USER/lte-softmodem.h" - - - /*------------------------------------------------------------------------------*/ diff --git a/openair2/ENB_APP/flexran_agent.c b/openair2/ENB_APP/flexran_agent.c index 24ed07ac9255d0448af4d92c3f73ee1c31282e39..f73e808865b4b48218dc4ad54977d034db815908 100644 --- a/openair2/ENB_APP/flexran_agent.c +++ b/openair2/ENB_APP/flexran_agent.c @@ -28,12 +28,12 @@ #define _GNU_SOURCE #include "flexran_agent.h" +#include <common/utils/system.h> #include <pthread.h> #include <arpa/inet.h> void *receive_thread(void *args); -pthread_t new_thread(void *(*f)(void *), void *b); Protocol__FlexranMessage *flexran_agent_timeout(void* args); @@ -147,38 +147,6 @@ error: } -/* utility function to create a thread */ -pthread_t new_thread(void *(*f)(void *), void *b) { - pthread_t t; - pthread_attr_t att; - - if (pthread_attr_init(&att)){ - fprintf(stderr, "pthread_attr_init err\n"); - exit(1); - } - - struct sched_param sched_param_recv_thread; - - sched_param_recv_thread.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1; - pthread_attr_setschedparam(&att, &sched_param_recv_thread); - pthread_attr_setschedpolicy(&att, SCHED_FIFO); - - if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED)) { - fprintf(stderr, "pthread_attr_setdetachstate err\n"); - exit(1); - } - if (pthread_create(&t, &att, f, b)) { - fprintf(stderr, "pthread_create err\n"); - exit(1); - } - if (pthread_attr_destroy(&att)) { - fprintf(stderr, "pthread_attr_destroy err\n"); - exit(1); - } - - return t; -} - int channel_container_init = 0; int flexran_agent_start(mid_t mod_id) { @@ -235,12 +203,9 @@ int flexran_agent_start(mid_t mod_id) */ /*Initialize the continuous stats update mechanism*/ - if (flexran_agent_init_cont_stats_update(mod_id) < 0) { - LOG_E(FLEXRAN_AGENT, "could not initialize continuous stats updates\n"); - goto error; - } - - new_thread(receive_thread, flexran); + flexran_agent_init_cont_stats_update(mod_id); + pthread_t t; + threadCreate(&t, receive_thread, flexran, "flexran", -1, OAI_PRIORITY_RT); /* Register and initialize the control modules depending on capabilities. * After registering, calling flexran_agent_get_*_xface() tells whether a diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 860f90bf34e85f4511a2bc3cd4b23673225f8b50..8e67e1f637b8bea6072a5e2c56886634ae2fb0c0 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -83,7 +83,6 @@ typedef struct { uint64_t get_pdcp_optmask(void); extern pthread_t pdcp_thread; -extern pthread_attr_t pdcp_thread_attr; extern pthread_mutex_t pdcp_mutex; extern pthread_cond_t pdcp_cond; extern int pdcp_instance_cnt; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c index f47694c2e31a8928f74b7266052022d8482d15cf..6dd3846d886277979019a131f2758aeab4d8e217 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_netlink.c @@ -96,8 +96,7 @@ pdcp_netlink_init( int i; int nb_inst_enb; int nb_inst_ue; - pthread_attr_t attr; - struct sched_param sched_param; + reset_meas(&ip_pdcp_stats_tmp); nb_inst_enb = 1; nb_inst_ue = 1; @@ -137,27 +136,11 @@ pdcp_netlink_init( } if ((nb_inst_ue + nb_inst_enb) > 0) { - if (pthread_attr_init(&attr) != 0) { - LOG_E(PDCP, "[NETLINK]Failed to initialize pthread attribute for Netlink -> PDCP communication (%d:%s)\n", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - sched_param.sched_priority = 10; - pthread_attr_setschedpolicy(&attr, SCHED_RR); - pthread_attr_setschedparam(&attr, &sched_param); - /* Create one thread that fetchs packets from the netlink. * When the netlink fifo is full, packets are silently dropped, this behaviour * should be avoided if we want a reliable link. */ - if (pthread_create(&pdcp_netlink_thread, &attr, pdcp_netlink_thread_fct, NULL) != 0) { - LOG_E(PDCP, "[NETLINK]Failed to create new thread for Netlink/PDCP communication (%d:%s)\n", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - pthread_setname_np( pdcp_netlink_thread, "PDCP netlink" ); + threadCreate(&pdcp_netlink_thread, pdcp_netlink_thread_fct, "PDCP netlink", -1, OAI_PRIORITY_RT_LOW ); } return 0; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c index 0b6be93d59a5f44448282293529f0c1ff337e95b..f1f6ebb7941502e5ae176ce218f72922ab600b91 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_thread.c @@ -45,7 +45,6 @@ extern int oai_exit; extern char UE_flag; pthread_t pdcp_thread; -pthread_attr_t pdcp_thread_attr; pthread_mutex_t pdcp_mutex; pthread_cond_t pdcp_cond; int pdcp_instance_cnt; @@ -101,33 +100,12 @@ static void *pdcp_thread_main(void* param) int init_pdcp_thread(void) { - int error_code; - struct sched_param p; - - pthread_attr_init (&pdcp_thread_attr); - pthread_attr_setstacksize(&pdcp_thread_attr,OPENAIR_THREAD_STACK_SIZE); - //attr_dlsch_threads.priority = 1; - - p.sched_priority = OPENAIR_THREAD_PRIORITY; - pthread_attr_setschedparam (&pdcp_thread_attr, &p); - pthread_attr_setschedpolicy (&pdcp_thread_attr, SCHED_FIFO); pthread_mutex_init(&pdcp_mutex,NULL); pthread_cond_init(&pdcp_cond,NULL); pdcp_instance_cnt = -1; LOG_I(PDCP,"Allocating PDCP thread\n"); - error_code = pthread_create(&pdcp_thread, - &pdcp_thread_attr, - pdcp_thread_main, - (void*)NULL); - - if (error_code!= 0) { - LOG_I(PDCP,"Could not allocate PDCP thread, error %d\n",error_code); - return(error_code); - } else { - LOG_I(PDCP,"Allocate PDCP thread successful\n"); - pthread_setname_np( pdcp_thread, "PDCP" ); - } + threadCreate(&pdcp_thread, pdcp_thread_main, (void*)NULL, "PDCP", -1, OAI_PRIORITY_RT); return(0); } diff --git a/openair2/PHY_INTERFACE/UE_MAC_interface.h b/openair2/PHY_INTERFACE/UE_MAC_interface.h index 3d6a8ced82c8c458cd854d51d9098ef481aad62f..42e790d1e96c188bf82e3a96ef2e14ef2b1499fa 100644 --- a/openair2/PHY_INTERFACE/UE_MAC_interface.h +++ b/openair2/PHY_INTERFACE/UE_MAC_interface.h @@ -40,8 +40,6 @@ #include "openair1/PHY/defs_RU.h" #include "targets/COMMON/openairinterface5g_limits.h" - - #define MAX_NUM_DL_PDU 100 #define MAX_NUM_UL_PDU 100 #define MAX_NUM_HI_DCI0_PDU 100 diff --git a/openair2/RRC/LTE/defs_NB_IoT.h b/openair2/RRC/LTE/defs_NB_IoT.h index 26eca6d781fd246814f65eaa3a8189b530c07595..8f0c4d16e664e7bb0fe1ceb74109939113c8e167 100644 --- a/openair2/RRC/LTE/defs_NB_IoT.h +++ b/openair2/RRC/LTE/defs_NB_IoT.h @@ -42,7 +42,7 @@ #include "rrc_types_NB_IoT.h" #include "COMMON/platform_constants.h" #include "COMMON/platform_types.h" -#include "targets/COMMON/openairinterface5g_limits.h" +#include "openairinterface5g_limits.h" #include "COMMON/mac_rrc_primitives.h" diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index 2e3d0a8bc788d3314495840f62ef7a566b2f4aad..621a0d3b682d2e0328301aac491dc85ee398d379 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -74,6 +74,7 @@ #include "pdcp.h" #include "plmn_data.h" #include "msc.h" +#include <common/utils/system.h> #include "intertask_interface.h" @@ -4953,7 +4954,6 @@ rrc_ue_process_sidelink_radioResourceConfig( } else { //SL_DiscConfig_r12__ext2__discTxResourcesPS_r13__setup_PR_NOTHING, /* No components present */ } - break; case LTE_SL_DiscConfig_r12__ext2__discTxResourcesPS_r13_PR_release: @@ -4972,58 +4972,37 @@ rrc_ue_process_sidelink_radioResourceConfig( #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0)) //----------------------------------------------------------- -void -rrc_control_socket_init() { +void rrc_control_socket_init() { struct sockaddr_in rrc_ctrl_socket_addr; - pthread_attr_t attr; - struct sched_param sched_param; int optval; // flag value for setsockopt //int n; // message byte size + // create the control socket ctrl_sock_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (ctrl_sock_fd == -1) { - LOG_E(RRC,"[rrc_control_socket_init] :Error opening socket %d (%d:%s)\n",ctrl_sock_fd,errno, strerror(errno)); + LOG_E(RRC,"[rrc_control_socket_init] :Error opening socket %d (%d:%s)\n", ctrl_sock_fd, errno, strerror(errno)); exit(EXIT_FAILURE); } // if (ctrl_sock_fd < 0) // error("ERROR: Failed on opening socket"); optval = 1; - setsockopt(ctrl_sock_fd, SOL_SOCKET, SO_REUSEADDR, - (const void *)&optval, sizeof(int)); - //build the server's address + setsockopt(ctrl_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int)); + //build the server's address bzero((char *) &rrc_ctrl_socket_addr, sizeof(rrc_ctrl_socket_addr)); rrc_ctrl_socket_addr.sin_family = AF_INET; rrc_ctrl_socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); rrc_ctrl_socket_addr.sin_port = htons(CONTROL_SOCKET_PORT_NO); // associate the parent socket with a port - if (bind(ctrl_sock_fd, (struct sockaddr *) &rrc_ctrl_socket_addr, - sizeof(rrc_ctrl_socket_addr)) < 0) { + if (bind(ctrl_sock_fd, (struct sockaddr *) &rrc_ctrl_socket_addr, sizeof(rrc_ctrl_socket_addr)) < 0) { LOG_E(RRC,"[rrc_control_socket_init] ERROR: Failed on binding the socket\n"); exit(1); } - //create thread to listen to incoming packets - if (pthread_attr_init(&attr) != 0) { - LOG_E(RRC, "[rrc_control_socket_init]Failed to initialize pthread attribute for ProSe -> RRC communication (%d:%s)\n", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - sched_param.sched_priority = 10; - pthread_attr_setschedpolicy(&attr, SCHED_RR); - pthread_attr_setschedparam(&attr, &sched_param); - pthread_t rrc_control_socket_thread; - - if (pthread_create(&rrc_control_socket_thread, &attr, rrc_control_socket_thread_fct, NULL) != 0) { - LOG_E(RRC, "[rrc_control_socket_init]Failed to create new thread for RRC/ProSeApp communication (%d:%s)\n", - errno, strerror(errno)); - exit(EXIT_FAILURE); - } + pthread_t rrc_control_socket_thread; - pthread_setname_np( rrc_control_socket_thread, "RRC Control Socket" ); + threadCreate(&rrc_control_socket_thread, rrc_control_socket_thread_fct, NULL, "RRC/ProSeApp", -1, OAI_PRIORITY_RT); } //-------------------------------------------------------- diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6b1ded3b1e375c110213fbe518fcc158f7126d86..749320b3572662a1c4cb7754b7046f4010211603 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -116,10 +116,9 @@ mui_t rrc_gNB_mui = 0; void openair_nr_rrc_on(const protocol_ctxt_t* const ctxt_pP){ - int CC_id; LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_FMT" gNB:OPENAIR NR RRC IN....\n",PROTOCOL_NR_RRC_CTXT_ARGS(ctxt_pP)); - for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { rrc_config_nr_buffer (&RC.nrrrc[ctxt_pP->module_id]->carrier[CC_id].SI, BCCH, 1); RC.nrrrc[ctxt_pP->module_id]->carrier[CC_id].SI.Active = 1; rrc_config_nr_buffer (&RC.nrrrc[ctxt_pP->module_id]->carrier[CC_id].Srb0, CCCH, 1); diff --git a/openair2/UTIL/ASYNC_IF/link_manager.c b/openair2/UTIL/ASYNC_IF/link_manager.c index e9a8e98e0768b282975a3c3b5f9a3223d0535eaf..85a4f48a8e42c0fc44a0af86a3f75404280887c2 100644 --- a/openair2/UTIL/ASYNC_IF/link_manager.c +++ b/openair2/UTIL/ASYNC_IF/link_manager.c @@ -30,6 +30,8 @@ #include "link_manager.h" #include "common/utils/LOG/log.h" +#include <common/utils/assertions.h> +#include <common/utils/system.h> #include <stdio.h> #include <stdlib.h> @@ -98,47 +100,21 @@ link_manager_t *create_link_manager( LOG_D(MAC, "create new link manager\n"); - ret = calloc(1, sizeof(link_manager_t)); - if (ret == NULL) - goto error; + AssertFatal( (ret=calloc(1, sizeof(link_manager_t))) != NULL,""); ret->send_queue = send_queue; ret->receive_queue = receive_queue; ret->socket_link = link; ret->run = 1; - if (pthread_attr_init(&attr)) - goto error; - - // Make the async interface threads real-time - //#ifndef LOWLATENCY - struct sched_param sched_param_recv_thread; - - sched_param_recv_thread.sched_priority = sched_get_priority_max(SCHED_RR) - 1; - pthread_attr_setschedparam(&attr, &sched_param_recv_thread); - pthread_attr_setschedpolicy(&attr, SCHED_RR); - //#endif - - if (pthread_create(&t, &attr, link_manager_sender_thread, ret)) - goto error; + threadCreate(&t, link_manager_sender_thread, ret, "flexranSender", -1, OAI_PRIORITY_RT_LOW); ret->sender = t; - if (pthread_create(&t, &attr, link_manager_receiver_thread, ret)) - /* we should destroy the other thread here */ - goto error; + threadCreate(&t, link_manager_receiver_thread, ret, "flexranReceiver", -1, OAI_PRIORITY_RT_LOW); ret->receiver = t; - if (pthread_attr_destroy(&attr)) - /* to be clean we should destroy the threads at this point, - * even if in practice we never reach it */ - goto error; - return ret; -error: - LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); - free(ret); - return NULL; } void destroy_link_manager(link_manager_t *manager) diff --git a/openair2/UTIL/CLI/cli_server.c b/openair2/UTIL/CLI/cli_server.c index d4f97f15ba0f6e10ba18fdddda7d8783024c3b6a..1994855b5d8b4beaa326462fb94575569accf249 100644 --- a/openair2/UTIL/CLI/cli_server.c +++ b/openair2/UTIL/CLI/cli_server.c @@ -90,10 +90,7 @@ int cli_server_init(cli_handler_t handler) } /* create telnet listener thread */ - if (pthread_create(&cli_server_listener, NULL, cli_server_listen, NULL)) { - perror("thread"); - return -1; - } + threadCreate(&cli_server_listener, cli_server_listen, NULL, "telnet", -1, OAI_PRIORITY_RT_LOW); return 0; } diff --git a/openair2/UTIL/OPT/probe.c b/openair2/UTIL/OPT/probe.c index b032784028ee4dc7f2349e615cc7bbef5a6cbc6d..0058d25b122286d7d207d2be354dd3288441ad15 100644 --- a/openair2/UTIL/OPT/probe.c +++ b/openair2/UTIL/OPT/probe.c @@ -90,8 +90,9 @@ what about the implementation #include <pthread.h> #include <stdint.h> -#include "common/config/config_userapi.h" #include "opt.h" +#include "common/config/config_userapi.h" +#include "common/utils/system.h" int opt_enabled=0; @@ -196,15 +197,7 @@ int opt_create_listener_socket(char *ip_address, uint16_t port) { return -1; } - ret = pthread_create(&opt_listener.thread, NULL, opt_listener_thread, NULL); - - if (ret != 0) { - LOG_E(OPT, "Failed to create thread for server socket: %s\n", strerror(errno)); - opt_type = OPT_NONE; - close(opt_listener.sd); - opt_listener.sd = -1; - return -1; - } + threadCreate(&opt_listener.thread, opt_listener_thread, NULL, "flexran", -1, OAI_PRIORITY_RT_LOW); return 0; } diff --git a/openair2/UTIL/OTG/otg_rx_socket.c b/openair2/UTIL/OTG/otg_rx_socket.c index 88ecd3e9044909246483c97344e6e4c298a513ab..9e9b6bf4a1d1481f3f768e7c3d87fe0627ed6990 100644 --- a/openair2/UTIL/OTG/otg_rx_socket.c +++ b/openair2/UTIL/OTG/otg_rx_socket.c @@ -195,17 +195,7 @@ void server_socket_tcp_ip4() /* create new thread for the new connection */ - if (pthread_create(&id, NULL, (void *)recv_ip4_tcp, (void*)csock)) - LOG_W(OTG,"SOCKET:: TCP-IP4 ::pthread_create OK!\n"); - - else - LOG_W(OTG,"SOCKET:: TCP-IP4 ::Error in pthread_create \n"); - - if (pthread_detach(id)) - LOG_W(OTG,"SOCKET:: TCP-IP4 ::pthread_detach OK!\n"); - else - LOG_W(OTG,"SOCKET:: TCP-IP4 ::Error in pthread_detach\n"); - + threadCreate(&id, (void *)recv_ip4_tcp, (void*)csock), "OTG", -1, OAI_PRIORITY_RT_LOW); LOG_I(OTG,"SOCKET:: TCP-IP4 :: Client n=%d finish transmission\n", cmpt_cl); cmpt_cl+=1; } diff --git a/openair3/NAS/COMMON/UTIL/nas_timer.c b/openair3/NAS/COMMON/UTIL/nas_timer.c index d92c48f483c25366334ac4a654aa23890056c7e8..7ddcb61d1dc1cca7f1839ed07883b5dac1ec37d9 100644 --- a/openair3/NAS/COMMON/UTIL/nas_timer.c +++ b/openair3/NAS/COMMON/UTIL/nas_timer.c @@ -397,24 +397,14 @@ static void _nas_timer_handler(int signal) /* Get the timer entry for which the system timer expired */ nas_timer_entry_t *te = _nas_timer_db.head->entry; - /* Execute the callback function */ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - int rc = pthread_create (&te->pid, &attr, te->cb, te->args); - pthread_attr_destroy(&attr); - - /* Wait for the thread to terminate before releasing the timer entry */ - if (rc == 0) { + threadCreate (&te->pid, te->cb, te->args, "nas-timer", -1, OAI_PRIORITY_RT_LOW); + void *result = NULL; (void) pthread_join(te->pid, &result); - /* TODO: Check returned result ??? */ if (result) { free(result); } - } } #endif diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 6a70911e21d830616ec37303eb7ce981a72149b2..7fe1435960ffe804372171180de6f7640f4960d4 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -150,39 +150,20 @@ int main(int argc, const char *argv[]) (void) _nas_set_signal_handler (SIGINT, _nas_signal_handler); (void) _nas_set_signal_handler (SIGTERM, _nas_signal_handler); - pthread_attr_t attr; - pthread_attr_init (&attr); - pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - /* * Start thread use to manage the user connection endpoint */ pthread_t user_mngr; - if (pthread_create (&user_mngr, &attr, _nas_user_mngr, &user_fd) != 0) { - LOG_TRACE (ERROR, "UE-MAIN - " - "Failed to create the user management thread"); - user_api_close (user_api_id); - network_api_close (network_fd); - exit (EXIT_FAILURE); - } + threadCreate (&user_mngr, , _nas_user_mngr, &user_fd, "UE-nas", -1, OAI_PRIORITY_RT_LOW) ; /* * Start thread use to manage the network connection endpoint */ pthread_t network_mngr; - if (pthread_create (&network_mngr, &attr, _nas_network_mngr, - &network_fd) != 0) { - LOG_TRACE (ERROR, "UE-MAIN - " - "Failed to create the network management thread"); - user_api_close (user_api_id); - network_api_close (network_fd); - exit (EXIT_FAILURE); - } - - pthread_attr_destroy (&attr); + threadCreate (&network_mngr, _nas_network_mngr, + &network_fd, "UE-nas-mgr", -1, OAI_PRIORITY_RT_LOW) ; /* * Suspend execution of the main process until all connection diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 4b0945f5eaaccedacf4b45810900e1a8cc35987a..32b38a45286db9931b69ae0015035057cd69be31 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -40,6 +40,7 @@ #include <arpa/inet.h> #include "assertions.h" +#include "common/utils/system.h" #include "queue.h" #include "intertask_interface.h" diff --git a/targets/ARCH/COMMON/common_lib.h b/targets/ARCH/COMMON/common_lib.h index e63cef08b23cc15f4eb7d1307a32e2ba1cd12396..8094b15cc8f1f98304852ab65be798d7d07156e1 100644 --- a/targets/ARCH/COMMON/common_lib.h +++ b/targets/ARCH/COMMON/common_lib.h @@ -58,11 +58,6 @@ typedef volatile int64_t openair0_vtimestamp; /*!\brief structrue holds the parameters to configure USRP devices*/ typedef struct openair0_device_t openair0_device; - - - - - //#define USRP_GAIN_OFFSET (56.0) // 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output typedef enum { @@ -83,9 +78,6 @@ typedef enum { */ /*!\brief RF device types */ -#ifdef OCP_FRAMEWORK -#include <enums.h> -#else typedef enum { MIN_RF_DEV_TYPE = 0, /*!\brief device is ExpressMIMO */ @@ -109,7 +101,6 @@ typedef enum { MAX_RF_DEV_TYPE } dev_type_t; -#endif /*!\brief transport protocol types */ @@ -209,7 +200,7 @@ typedef struct { //! clock source clock_source_t clock_source; //! Manual SDR IP address -//#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) + //#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) char *sdr_addrs; //! Auto calibration flag int autocal[4]; @@ -235,7 +226,7 @@ typedef struct { unsigned int sf_read_delay; // read delay in replay mode unsigned int sf_write_delay; // write delay in replay mode unsigned int eth_mtu; // ethernet MTU -#endif +#endif //! number of samples per tti unsigned int samples_per_tti; @@ -408,6 +399,32 @@ typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t * /* type of transport init function, implemented in shared lib */ typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params); +#define UE_MAGICDL_FDD 0xA5A5A5A5A5A5A5A5 // UE DL FDD record +#define UE_MAGICUL_FDD 0x5A5A5A5A5A5A5A5A // UE UL FDD record +#define UE_MAGICDL_TDD 0xA6A6A6A6A6A6A6A6 // UE DL TDD record +#define UE_MAGICUL_TDD 0x6A6A6A6A6A6A6A6A // UE UL TDD record + +#define ENB_MAGICDL_FDD 0xB5B5B5B5B5B5B5B5 // eNB DL FDD record +#define ENB_MAGICUL_FDD 0x5B5B5B5B5B5B5B5B // eNB UL FDD record +#define ENB_MAGICDL_TDD 0xB6B6B6B6B6B6B6B6 // eNB DL TDD record +#define ENB_MAGICUL_TDD 0x6B6B6B6B6B6B6B6B // eNB UL TDD record + +#define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size) + +#define sample_t uint32_t // 2*16 bits complex number + +typedef struct { + uint64_t magic; // Magic value (see defines above) + uint32_t size; // Number of samples per antenna to follow this header + uint32_t nbAnt; // Total number of antennas following this header + // Samples per antenna follow this header, + // i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1 + // data following this header in bytes is nbAnt*size*sizeof(sample_t) + uint64_t timestamp; // Timestamp value of first sample + uint32_t option_value; // Option value + uint32_t option_flag; // Option flag +} samplesBlockHeader_t; + #ifdef __cplusplus extern "C" { @@ -432,6 +449,7 @@ openair0_timestamp get_usrp_time(openair0_device *device); */ int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg); +#define gettid() syscall(__NR_gettid) /*@}*/ #ifdef __cplusplus diff --git a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp index 384542a70f0d2e65ae7b32afa202a38e2149e096..9ac5ddf0dafdea557674840eede3f16e35f174c7 100644 --- a/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp +++ b/targets/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp @@ -304,6 +304,7 @@ static int trx_usrp_start(openair0_device *device) { if (u_sf_mode != 2) { // not replay mode #endif + uhd::set_thread_priority_safe(1.0); usrp_state_t *s = (usrp_state_t *)device->priv; // setup GPIO for TDD, GPIO(4) = ATR_RX //set data direction register (DDR) to output @@ -1048,7 +1049,6 @@ extern "C" { << use_mmap << std::endl; } else { #endif - uhd::set_thread_priority_safe(1.0); usrp_state_t *s = (usrp_state_t *)calloc(sizeof(usrp_state_t),1); if (openair0_cfg[0].clock_source==gpsdo) @@ -1112,6 +1112,9 @@ extern "C" { device->type=USRP_X300_DEV; usrp_master_clock = 184.32e6; args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock); + // USRP recommended: https://files.ettus.com/manual/page_usrp_x3x0_config.html + if ( 0 != system("sysctl -w net.core.rmem_max=33554432 net.core.wmem_max=33554432") ) + LOG_W(HW,"Can't set kernel paramters for X3xx\n"); } s->usrp = uhd::usrp::multi_usrp::make(args); diff --git a/targets/ARCH/rfsimulator/simulator.c b/targets/ARCH/rfsimulator/simulator.c index a17327b03ecc5791cadc7cef76fbecc9d3205da8..099e1c190aa42996bf696ffad4575a2060d19735 100644 --- a/targets/ARCH/rfsimulator/simulator.c +++ b/targets/ARCH/rfsimulator/simulator.c @@ -27,22 +27,15 @@ #define sample_t uint32_t // 2*16 bits complex number #define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t)) #define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) -#define MAGICeNB 0xA5A5A5A5A5A5A5A5 -#define MAGICUE 0x5A5A5A5A5A5A5A5A -typedef struct { - uint64_t magic; - uint32_t size; - uint32_t nbAnt; - uint64_t timestamp; -} transferHeader; +#define sample_t uint32_t // 2*16 bits complex number typedef struct buffer_s { int conn_sock; bool alreadyRead; uint64_t lastReceivedTS; bool headerMode; - transferHeader th; + samplesBlockHeader_t th; char *transferPtr; uint64_t remainToTransfer; char *circularBufEnd; @@ -53,8 +46,8 @@ typedef struct { int listen_sock, epollfd; uint64_t nextTimestamp; uint64_t typeStamp; - uint64_t initialAhead; char *ip; + int saveIQfile; buffer_t buf[FD_SETSIZE]; } rfsimulator_state_t; @@ -63,9 +56,11 @@ void allocCirBuf(rfsimulator_state_t *bridge, int sock) { AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, ""); ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); ptr->conn_sock=sock; + ptr->alreadyRead=false; + ptr->lastReceivedTS=0; ptr->headerMode=true; ptr->transferPtr=(char *)&ptr->th; - ptr->remainToTransfer=sizeof(transferHeader); + ptr->remainToTransfer=sizeof(samplesBlockHeader_t); int sendbuff=1000*1000*10; AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, ""); struct epoll_event ev= {0}; @@ -87,12 +82,11 @@ void socketError(rfsimulator_state_t *bridge, int sock) { LOG_W(HW,"Lost socket \n"); removeCirBuf(bridge, sock); - if (bridge->typeStamp==MAGICUE) + if (bridge->typeStamp==UE_MAGICDL_FDD) exit(1); } } - #define helpTxt "\ \x1b[31m\ rfsimulator: error: you have to run one UE and one eNB\n\ @@ -119,9 +113,17 @@ void setblocking(int sock, enum blocking_t active) { static bool flushInput(rfsimulator_state_t *t); -void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { +void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) { + if (t->saveIQfile != -1) { + if (write(t->saveIQfile, _buf, count) != count ) + LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno)); + } + + AssertFatal(fd>=0 && _buf && count >0 && t, + "Bug: %d/%p/%zd/%p", fd, _buf, count, t); + char *buf = _buf; - int l; + ssize_t l; setblocking(fd, notBlocking); while (count) { @@ -145,7 +147,7 @@ void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) { int server_start(openair0_device *device) { rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; - t->typeStamp=MAGICeNB; + t->typeStamp=ENB_MAGICDL_FDD; AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); int enable = 1; AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, ""); @@ -168,7 +170,7 @@ sin_addr: int start_ue(openair0_device *device) { rfsimulator_state_t *t = device->priv; - t->typeStamp=MAGICUE; + t->typeStamp=UE_MAGICDL_FDD; int sock; AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); struct sockaddr_in addr = { @@ -200,14 +202,16 @@ sin_addr: return 0; } +uint64_t lastW=-1; int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { rfsimulator_state_t *t = device->priv; + LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp); for (int i=0; i<FD_SETSIZE; i++) { buffer_t *ptr=&t->buf[i]; if (ptr->conn_sock >= 0 ) { - transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp}; + samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp}; fullwrite(ptr->conn_sock,&header, sizeof(header), t); sample_t tmpSamples[nsamps][nbAnt]; @@ -222,7 +226,7 @@ int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, voi fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t); } } - + lastW=timestamp; LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) ); return nsamps; @@ -232,7 +236,7 @@ static bool flushInput(rfsimulator_state_t *t) { // Process all incoming events on sockets // store the data in lists struct epoll_event events[FD_SETSIZE]= {0}; - int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200); + int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 20); if ( nfds==-1 ) { if ( errno==EINTR || errno==EAGAIN ) @@ -263,7 +267,7 @@ static bool flushInput(rfsimulator_state_t *t) { continue; } - int blockSz; + ssize_t blockSz; if ( b->headerMode) blockSz=b->remainToTransfer; @@ -272,7 +276,7 @@ static bool flushInput(rfsimulator_state_t *t) { b->remainToTransfer : b->circularBufEnd - 1 - b->transferPtr ; - int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT); + ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT); if ( sz < 0 ) { if ( errno != EAGAIN ) { @@ -282,6 +286,7 @@ static bool flushInput(rfsimulator_state_t *t) { } else if ( sz == 0 ) continue; + LOG_D(HW, "Socket rcv %zd bytes\n", sz); AssertFatal((b->remainToTransfer-=sz) >= 0, ""); b->transferPtr+=sz; @@ -290,8 +295,8 @@ static bool flushInput(rfsimulator_state_t *t) { // check the header and start block transfer if ( b->headerMode==true && b->remainToTransfer==0) { - AssertFatal( (t->typeStamp == MAGICUE && b->th.magic==MAGICeNB) || - (t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol"); + AssertFatal( (t->typeStamp == UE_MAGICDL_FDD && b->th.magic==ENB_MAGICDL_FDD) || + (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol"); b->headerMode=false; b->alreadyRead=true; @@ -306,23 +311,24 @@ static bool flushInput(rfsimulator_state_t *t) { } b->lastReceivedTS=b->th.timestamp; + AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize), + "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS); b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize]; b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); } if ( b->headerMode==false ) { + LOG_D(HW,"Set b->lastReceivedTS %ld\n", b->lastReceivedTS); b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); - + // First block in UE, resync with the eNB current TS + if ( t->nextTimestamp == 0 ) + t->nextTimestamp=b->lastReceivedTS-b->th.size; + if ( b->remainToTransfer==0) { LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS); - - // First block in UE, resync with the eNB current TS - if ( t->nextTimestamp == 0 ) - t->nextTimestamp=b->lastReceivedTS-b->th.size; - b->headerMode=true; b->transferPtr=(char *)&b->th; - b->remainToTransfer=sizeof(transferHeader); + b->remainToTransfer=sizeof(samplesBlockHeader_t); b->th.magic=-1; } } @@ -365,13 +371,14 @@ int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, vo do { have_to_wait=false; - for ( int sock=0; sock<FD_SETSIZE; sock++) - if ( t->buf[sock].circularBuf && - t->buf[sock].alreadyRead && //>= t->initialAhead && - (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { - have_to_wait=true; - break; - } + for ( int sock=0; sock<FD_SETSIZE; sock++) { + if ( t->buf[sock].circularBuf && t->buf[sock].alreadyRead ) + if ( t->buf[sock].lastReceivedTS == 0 || + (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) { + have_to_wait=true; + break; + } + } if (have_to_wait) /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n", @@ -439,6 +446,7 @@ int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_c __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { //set_log(HW,OAILOG_DEBUG); + //set_log(PHY,OAILOG_DEBUG); rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1); if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) { @@ -446,11 +454,26 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { exit(1); } - rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ? - MAGICeNB: - MAGICUE; - LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE"); - device->trx_start_func = rfsimulator->typeStamp == MAGICeNB ? + if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 || + strncasecmp(rfsimulator->ip,"server",3) == 0 ) + rfsimulator->typeStamp = ENB_MAGICDL_FDD; + else + rfsimulator->typeStamp = UE_MAGICDL_FDD; + + LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE"); + char *saveF; + + if ((saveF=getenv("saveIQfile")) != NULL) { + rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666); + + if ( rfsimulator->saveIQfile != -1 ) + LOG_I(HW,"rfsimulator: will save written IQ samples in %s\n", saveF); + else + LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno)); + } else + rfsimulator->saveIQfile = -1; + + device->trx_start_func = rfsimulator->typeStamp == ENB_MAGICDL_FDD ? server_start : start_ue; device->trx_get_stats_func = rfsimulator_get_stats; @@ -470,6 +493,5 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { rfsimulator->buf[i].conn_sock=-1; AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,""); - rfsimulator->initialAhead=openair0_cfg[0].sample_rate/1000; // One sub frame return 0; } diff --git a/targets/ARCH/rfsimulator/stored_node.c b/targets/ARCH/rfsimulator/stored_node.c new file mode 100644 index 0000000000000000000000000000000000000000..888b5f6de0d2d1224ed99c0fe34d49f1900b312e --- /dev/null +++ b/targets/ARCH/rfsimulator/stored_node.c @@ -0,0 +1,142 @@ +/* + Author: Laurent THOMAS, Open Cells + copyleft: OpenAirInterface Software Alliance and it's licence +*/ + +#include <common/utils/simple_executable.h> + + +void fullwrite(int fd, void *_buf, int count) { + char *buf = _buf; + int l; + + while (count) { + l = write(fd, buf, count); + + if (l <= 0) { + if (errno==EINTR) + continue; + + if(errno==EAGAIN) { + continue; + } else { + AssertFatal(false,"Lost socket\n"); + } + } else { + count -= l; + buf += l; + } + } +} + +int server_start(short port) { + int listen_sock; + AssertFatal((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); + int enable = 1; + AssertFatal(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, ""); + struct sockaddr_in addr = { +sin_family: + AF_INET, +sin_port: + htons(port), +sin_addr: + { s_addr: INADDR_ANY } + }; + bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)); + AssertFatal(listen(listen_sock, 5) == 0, ""); + return accept(listen_sock,NULL,NULL); +} + +int client_start(char *IP, short port) { + int sock; + AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, ""); + struct sockaddr_in addr = { +sin_family: + AF_INET, +sin_port: + htons(port), +sin_addr: + { s_addr: INADDR_ANY } + }; + addr.sin_addr.s_addr = inet_addr(IP); + bool connected=false; + + while(!connected) { + LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", IP, port); + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { + LOG_I(HW,"rfsimulator: connection established\n"); + connected=true; + } + + perror("simulated node"); + sleep(1); + } + + return sock; +} + +enum blocking_t { + notBlocking, + blocking +}; + +void setblocking(int sock, enum blocking_t active) { + int opts; + AssertFatal( (opts = fcntl(sock, F_GETFL)) >= 0,""); + + if (active==blocking) + opts = opts & ~O_NONBLOCK; + else + opts = opts | O_NONBLOCK; + + AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, ""); +} + +int main(int argc, char *argv[]) { + if(argc != 4) { + printf("Need parameters: source file, server or destination IP, TCP port\n"); + exit(1); + } + + int fd; + AssertFatal((fd=open(argv[1],O_RDONLY)) != -1, "file: %s", argv[1]); + off_t fileSize=lseek(fd, 0, SEEK_END); + int serviceSock; + + if (strcmp(argv[2],"server")==0) { + serviceSock=server_start(atoi(argv[3])); + } else { + client_start(argv[2],atoi(argv[3])); + } + + samplesBlockHeader_t header; + int bufSize=100000; + void *buff=malloc(bufSize); + + while (1) { + //Rewind the file to loop on the samples + if ( lseek(fd, 0, SEEK_CUR) >= fileSize ) + lseek(fd, 0, SEEK_SET); + + // Read one block and send it + setblocking(serviceSock, blocking); + AssertFatal(read(fd,&header,sizeof(header)), ""); + fullwrite(serviceSock, &header, sizeof(header)); + int dataSize=sizeof(sample_t)*header.size*header.nbAnt; + + if (dataSize>bufSize) + buff=realloc(buff,dataSize); + + AssertFatal(read(fd,buff,dataSize) == dataSize, ""); + fullwrite(serviceSock, buff, dataSize); + // Purge incoming samples + setblocking(serviceSock, notBlocking); + + while(recv(serviceSock,buff, bufSize, MSG_DONTWAIT) > 0) { + } + } + + return 0; +} + diff --git a/targets/COMMON/openairinterface5g_limits.h b/targets/COMMON/openairinterface5g_limits.h index b55b4922c57bbf327f9ebc7b68afd2d4e2bfab10..8c37b10eb7ecc90f67042c60cc1f1d5fd532503f 100644 --- a/targets/COMMON/openairinterface5g_limits.h +++ b/targets/COMMON/openairinterface5g_limits.h @@ -14,10 +14,10 @@ // now , if we use --mu option in UE, compiling error will occur. // This problem will be fixed in the future. # ifndef UESIM_EXPANSION -# define NUMBER_OF_UE_MAX 16 -# define NUMBER_OF_NR_UE_MAX 16 -# define NUMBER_OF_CONNECTED_eNB_MAX 3 -# define NUMBER_OF_CONNECTED_gNB_MAX 3 +# define NUMBER_OF_UE_MAX 4 +# define NUMBER_OF_NR_UE_MAX 4 +# define NUMBER_OF_CONNECTED_eNB_MAX 1 +# define NUMBER_OF_CONNECTED_gNB_MAX 1 # else # define NUMBER_OF_UE_MAX 256 # define NUMBER_OF_NR_UE_MAX 16 diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c index feb11d6a79cbac82dfa92974c5cde4da47b2ab9f..f420bf519a4e0760c167c30284317c8da9a3ce50 100644 --- a/targets/RT/USER/lte-uesoftmodem.c +++ b/targets/RT/USER/lte-uesoftmodem.c @@ -369,15 +369,16 @@ static void *scope_thread(void *arg) { while (!oai_exit) { // dump_ue_stats (PHY_vars_UE_g[0][0], &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0],stats_buffer, 0, mode,rx_input_level_dBm); - //fl_set_object_label(form_stats->stats_text, stats_buffer); - fl_clear_browser(form_stats->stats_text); - fl_add_browser_line(form_stats->stats_text, stats_buffer); - phy_scope_UE(form_ue[0], - PHY_vars_UE_g[0][0], - 0, - 0,7); - // printf("%s",stats_buffer); - } + //fl_set_object_label(form_stats->stats_text, stats_buffer); + fl_clear_browser(form_stats->stats_text); + fl_add_browser_line(form_stats->stats_text, stats_buffer); + + phy_scope_UE(form_ue[0], + PHY_vars_UE_g[0][0], + 0, + 0, + 7); + usleep(10000); # ifdef ENABLE_XFORMS_WRITE_STATS @@ -799,7 +800,10 @@ int main( int argc, char **argv ) { } cpuf=get_cpu_freq_GHz(); -#ifndef DEADLINE_SCHEDULER + + +#if 0 // #ifndef DEADLINE_SCHEDULER + printf("NO deadline scheduler\n"); /* Currently we set affinity for UHD to CPU 0 for eNB/UE and only if number of CPUS >2 */ cpu_set_t cpuset; diff --git a/targets/RT/USER/nr-softmodem.c b/targets/RT/USER/nr-softmodem.c index 411281d72a28086f389a96228cb00bcd51e3eaae..40d4758847f59eff0d516a4155a4ddca63bd676f 100644 --- a/targets/RT/USER/nr-softmodem.c +++ b/targets/RT/USER/nr-softmodem.c @@ -1238,6 +1238,8 @@ int main( int argc, char **argv ) // wait for end of program printf("TYPE <CTRL-C> TO TERMINATE\n"); + fflush(stdout); + fflush(stderr); //getchar(); #if defined(ENABLE_ITTI)