diff --git a/CMakeLists.txt b/CMakeLists.txt index 70ea409d36..2730c510e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -979,6 +979,7 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c + ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c @@ -1038,11 +1039,11 @@ pkg_check_modules(lapacke REQUIRED lapacke) add_library(PHY_UE ${PHY_SRC_UE}) target_link_libraries(PHY_UE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs UTIL) -# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` will -# be empty for Ubuntu, a no-op +# RHEL needs also cblas, but Ubuntu does not have it. So `cblas_LIBRARIES` and +# `cblas_INCLUDE_DIRS` will be empty for Ubuntu, a no-op pkg_check_modules(cblas cblas) target_link_libraries(PHY_UE PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES}) -target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE_DIRS}) +target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${cblas_INCLUDE_DIRS} ${lapacke_INCLUDE_DIRS}) add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON}) target_link_libraries(PHY_NR_COMMON PUBLIC UTIL) diff --git a/ci-scripts/Jenkinsfile-cluster b/ci-scripts/Jenkinsfile-cluster deleted file mode 100644 index 174ccab62f..0000000000 --- a/ci-scripts/Jenkinsfile-cluster +++ /dev/null @@ -1,228 +0,0 @@ -#!/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 - */ - -// Location of the executor node -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -// Name of the resource -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -def directoryExistsGlob(fileNameWithGlob) { - /* if multiple directories match, will join their names and call fileExists() on that */ - def dir = sh returnStdout: true, script: 'find . -name \'' + fileNameWithGlob + '\' -type d' - dir = dir.replaceAll("\n", "").trim() - echo "matching '" + fileNameWithGlob + "' found: '" + dir + "'" - if (dir == "") - return false - return fileExists(dir) -} - -//------------------------------------------------------------------------------- -// Pipeline start -pipeline { - agent { - label pythonExecutor - } - options { - timestamps() - ansiColor('xterm') - lock(extra: lockResources) - } - - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ('Verify Parameters') { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - - JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"' - JOB_TIMESTAMP = JOB_TIMESTAMP.trim() - - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - echo "no eNB_SourceCodePath given" - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } else { - echo "no eNB_mergeRequest given - not merging develop" - } - - if (params.OC_Credentials == null) { - echo "no OC_Credentials given" - allParametersPresent = false - } - if (params.OC_ProjectName == null) { - echo "no OC_ProjectName given" - allParametersPresent = false - } - if (params.pythonTestXmlFile == null) { - echo "no pythonTestXmlFile given" - allParametersPresent = false - } - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - echo "Some parameters are missing" - sh "./ci-scripts/fail.sh" - } - } - } - } - - stage ("Deploy and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - mainPythonAllXmlFiles += "--XMLTestFile=" + xmlFile + " " - echo "Test XML file : ${xmlFile}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - } - stage ("Log Collection") { - steps { - script { - dir ('ci-scripts') { - if (directoryExistsGlob("build_log_*")) { - sh "zip -r -qq build_log_${env.BUILD_ID}.zip build_log_*/*" - sh "rm -rf build_log_*/" - archiveArtifacts artifacts: "build_log_${env.BUILD_ID}.zip" - } - if (directoryExistsGlob("test_log_*")) { - sh "zip -r -qq test_log_${env.BUILD_ID}.zip test_log_*/*" - sh "rm -rf test_log_*/" - archiveArtifacts artifacts: "test_log_${env.BUILD_ID}.zip" - } - if (fileExists("test_results.html")) { - sh "mv test_results.html test_results-${env.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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html" - } - } - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-nrue b/ci-scripts/Jenkinsfile-nrue deleted file mode 100644 index 3f7ef9b9ed..0000000000 --- a/ci-scripts/Jenkinsfile-nrue +++ /dev/null @@ -1,223 +0,0 @@ -#!/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 - */ - -// Location of the executor node -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -// Name of the resource -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -// Flags -def scmEvent = false -def upstreamEvent = false - -//------------------------------------------------------------------------------- -// Pipeline start -pipeline { - agent { - label pythonExecutor - } - options { - timestamps() - ansiColor('xterm') - lock(extra: lockResources) - } - - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ('Verify Parameters') { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - - JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"' - JOB_TIMESTAMP = JOB_TIMESTAMP.trim() - - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (params.OC_Credentials == null) { - allParametersPresent = false - } - if (params.OC_ProjectName == null) { - allParametersPresent = false - } - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - echo "Some parameters are missing" - sh "./ci-scripts/fail.sh" - } - } - } - } - - stage ("Deploy and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - } - stage ("Log Collection") { - steps { - script { - dir ('ci-scripts') { - // Zipping all archived log files - sh "mkdir test_logs" - sh "mv *.log* test_logs || true" - // Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip - if (fileExists('../cmake_targets/log')) { - sh "mv ../cmake_targets/log/* test_logs || true" - } - sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/" - sh "rm -rf *test_log*/" - if (fileExists("test_logs_${env.BUILD_ID}.zip")) { - archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip" - } - if (fileExists("test_results.html")) { - sh "mv test_results.html test_results-${env.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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html" - } - } - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-physim-deploy b/ci-scripts/Jenkinsfile-physim-deploy deleted file mode 100644 index e3d243d07b..0000000000 --- a/ci-scripts/Jenkinsfile-physim-deploy +++ /dev/null @@ -1,224 +0,0 @@ -#!/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 - */ - -// Location of the executor node -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -// Name of the resource -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -// Flags -def scmEvent = false -def upstreamEvent = false - -//------------------------------------------------------------------------------- -// Pipeline start -pipeline { - agent { - label pythonExecutor - } - options { - timestamps() - ansiColor('xterm') - lock(extra: lockResources) - } - - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ('Verify Parameters') { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - - JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"' - JOB_TIMESTAMP = JOB_TIMESTAMP.trim() - - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (params.OC_Credentials == null) { - allParametersPresent = false - } - if (params.OC_ProjectName == null) { - allParametersPresent = false - } - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - echo "Some parameters are missing" - sh "./ci-scripts/fail.sh" - } - } - } - } - - stage ("Deploy and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - } - stage ("Log Collection") { - steps { - script { - dir ('ci-scripts') { - // Zipping all archived log files - sh "mkdir test_logs" - sh "mv *.log* test_logs || true" - // Zip all log files matching cmake_targets/{*.log*,log/*} into test_logs_XXXX.zip - if (fileExists('../cmake_targets/log')) { - sh "mv ../cmake_targets/log/* test_logs || true" - } - sh "zip -r -qq test_logs_${env.BUILD_ID}.zip *test_log*/" - sh "rm -rf *test_log*/" - if (fileExists("test_logs_${env.BUILD_ID}.zip")) { - archiveArtifacts artifacts: "test_logs_${env.BUILD_ID}.zip" - } - if (fileExists("test_results.html")) { - sh "mv test_results.html test_results-${env.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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts artifacts: "test_results-${env.JOB_NAME}.html" - } - } - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-tmp-full-ran b/ci-scripts/Jenkinsfile-tmp-full-ran deleted file mode 100644 index 07b10ab980..0000000000 --- a/ci-scripts/Jenkinsfile-tmp-full-ran +++ /dev/null @@ -1,250 +0,0 @@ -#!/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 - */ - -// Template Jenkins Declarative Pipeline script to run Test w/ RF HW - -// Location of the python executor node shall be in the same subnet as the others servers -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Terminate Status -def termENB = 0 -def termStatusArray = new Boolean[termENB + 1] -termStatusArray[termENB] = false - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -def doEpcLogCollection = true - - - -pipeline { - agent { - label pythonExecutor - } - options { - ansiColor('xterm') - lock(extra: lockResources) - } - - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ("Verify Parameters") { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - currentBuild.result = 'ABORTED' - error('Stopping early because some parameters are missing') - } - } - } - } - stage ("Build and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - stage ("Terminate") { - parallel { - stage('Terminate eNB') { - steps { - echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - sh "python3 ci-scripts/main.py --mode=TerminateeNB" - } - post { - success { - script { - termStatusArray[termENB] = true - } - } - } - } - } - } - stage('Log Collection') { - parallel { - stage('Log Collection (eNB - Run)') { - steps { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - - 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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts "test_results-${JOB_NAME}.html" - } - } - } - } - } - } - } - - post { - always { - script { - if (params.pipelineZipsConsoleLog != null) { - if (params.pipelineZipsConsoleLog) { - echo "Archiving Jenkins console log" - sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true" - sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true" - if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip" - } - } - } - } - } - // Making sure that we really shutdown every thing before leaving - failure { - script { - if (!termStatusArray[termENB]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB" - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb b/ci-scripts/Jenkinsfile-tmp-multi-enb deleted file mode 100644 index c01c8daf7e..0000000000 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb +++ /dev/null @@ -1,225 +0,0 @@ -#!/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 - */ - -// Template Jenkins Declarative Pipeline script to run Test w/ RF HW - -// Location of the python executor node shall be in the same subnet as the others servers -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -pipeline { - agent { - label pythonExecutor - } - options { - ansiColor('xterm') - lock(extra: lockResources) - } - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ("Verify Parameters") { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - echo "Some parameters are missing" - sh "./ci-scripts/fail.sh" - } - } - } - } - stage ("Build and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - stage ("Terminate") { - parallel { - stage('Terminate eNB') { - steps { - echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - sh "python3 ci-scripts/main.py --mode=TerminateeNB" - } - } - } - } - stage('Log Collection') { - parallel { - stage('Log Collection (eNB - Run)') { - steps { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - - 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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts "test_results-${JOB_NAME}.html" - } - } - } - } - } - } - } - - post { - always { - script { - if (params.pipelineZipsConsoleLog != null) { - if (params.pipelineZipsConsoleLog) { - echo "Archiving Jenkins console log" - sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true" - sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true" - if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip" - } - } - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa deleted file mode 100644 index 67aa6b4511..0000000000 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa +++ /dev/null @@ -1,216 +0,0 @@ -#!/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 - */ - -// Template Jenkins Declarative Pipeline script to run Test w/ RF HW - -// Location of the python executor node shall be in the same subnet as the others servers -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess -def eNB_TargetBranch - -//Status fed to the database -def StatusForDb = "" - - -pipeline { - agent {label pythonExecutor} - options { - ansiColor('xterm') - lock(extra: lockResources) - } - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ("Verify Parameters") { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest!= null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - echo "Some parameters are missing" - sh "./ci-scripts/fail.sh" - } - } - } - } - stage ("Build and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - stage('Log Collection') { - parallel { - stage('Log Collection (eNB - Run)') { - steps { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - script { - if(fileExists("enb.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "enb.log.${env.BUILD_ID}.zip" - } - } - } - } - } - } - } - - post { - always { - script { - 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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts "test_results-${JOB_NAME}.html" - } - if (params.pipelineZipsConsoleLog != null) { - if (params.pipelineZipsConsoleLog) { - echo "Archiving Jenkins console log" - sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true" - sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true" - if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip" - } - } - } - } - } - } -} diff --git a/ci-scripts/Jenkinsfile-tmp-ran b/ci-scripts/Jenkinsfile-tmp-ran deleted file mode 100644 index 526899a5a2..0000000000 --- a/ci-scripts/Jenkinsfile-tmp-ran +++ /dev/null @@ -1,260 +0,0 @@ -#!/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 - */ - -// Template Jenkins Declarative Pipeline script to run Test w/ RF HW - -// Location of the python executor node shall be in the same subnet as the others servers -def pythonExecutor = params.pythonExecutor - -// Location of the test XML file to be run -def testXMLFile = params.pythonTestXmlFile -def mainPythonAllXmlFiles = "" -def buildStageStatus = true - -// Name of the test stage -def testStageName = params.pipelineTestStageName - -def lockResources = [] -if (params.LockResources != null && params.LockResources.trim().length() > 0) - params.LockResources.trim().split(",").each{lockResources += [resource: it.trim()]} - -// Terminate Status -def termUE = 0 -def termENB = 1 -def termSPGW = 2 -def termMME = 3 -def termHSS = 4 -def termStatusArray = new Boolean[termHSS + 1] -termStatusArray[termUE] = false -termStatusArray[termENB] = false -termStatusArray[termSPGW] = false -termStatusArray[termMME] = false -termStatusArray[termHSS] = false - -// Global Parameters. Normally they should be populated when the master job -// triggers the slave job with parameters -def eNB_Repository -def eNB_Branch -def eNB_CommitID -def eNB_AllowMergeRequestProcess = false -def eNB_TargetBranch - -def flexricOption = "" - -pipeline { - agent { - label pythonExecutor - } - options { - ansiColor('xterm') - lock(extra: lockResources) - } - stages { - stage("Build Init") { - steps { - // update the build name and description - buildName "${params.eNB_MR}" - buildDescription "Branch : ${params.eNB_Branch}" - } - } - stage ("Verify Parameters") { - steps { - script { - echo '\u2705 \u001B[32mVerify Parameters\u001B[0m' - def allParametersPresent = true - - // It is already to late to check it - if (params.pythonExecutor != null) { - echo "eNB CI executor node : ${pythonExecutor}" - } - // If not present picking a default Stage Name - if (params.pipelineTestStageName == null) { - // picking default - testStageName = 'Template Test Stage' - } - - if (params.LockResources == null) { - echo "no LockResources given" - allParametersPresent = false - } - if (params.eNB_SourceCodePath == null) { - allParametersPresent = false - } - // the following 4 parameters should be pushed by the master trigger - // if not present, take the job GIT variables (used for developing) - if (params.eNB_Repository == null) { - eNB_Repository = env.GIT_URL - } else { - eNB_Repository = params.eNB_Repository - } - echo "eNB_Repository : ${eNB_Repository}" - if (params.eNB_Branch == null) { - eNB_Branch = env.GIT_BRANCH - } else { - eNB_Branch = params.eNB_Branch - } - echo "eNB_Branch : ${eNB_Branch}" - if (params.eNB_CommitID == null) { - eNB_CommitID = env.GIT_COMMIT - } else { - eNB_CommitID = params.eNB_CommitID - } - echo "eNB_CommitID : ${eNB_CommitID}" - if (params.eNB_mergeRequest != null) { - eNB_AllowMergeRequestProcess = params.eNB_mergeRequest - if (eNB_AllowMergeRequestProcess) { - if (params.eNB_TargetBranch != null) { - eNB_TargetBranch = params.eNB_TargetBranch - } else { - eNB_TargetBranch = 'develop' - } - echo "eNB_TargetBranch : ${eNB_TargetBranch}" - } - } - - if (params.Flexric_Tag != null) { - echo "This pipeline is configured to run with a FlexRIC deployment." - echo "Appending FlexRicTag option to the list of options" - flexricOption = "--FlexRicTag=${params.Flexric_Tag}" - echo "Using new Flexric option: ${flexricOption}" - } - - if (allParametersPresent) { - echo "All parameters are present" - if (eNB_AllowMergeRequestProcess) { - sh "git fetch" - sh "./ci-scripts/doGitLabMerge.sh --src-branch ${eNB_Branch} --src-commit ${eNB_CommitID} --target-branch ${eNB_TargetBranch} --target-commit latest" - } else if (eNB_CommitID != 'develop') { - sh "git fetch" - sh "git checkout -f ${eNB_CommitID}" - } - } else { - error "Some parameters are missing" - } - } - } - } - stage ("Build and Test") { - steps { - script { - dir ('ci-scripts') { - echo "\u2705 \u001B[32m${testStageName}\u001B[0m" - // If not present picking a default XML file - if (params.pythonTestXmlFile == null) { - // picking default - testXMLFile = 'xml_files/enb_usrpB210_band7_50PRB.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}" - } else { - echo "Test XML file ${xmlFile}: no such file" - } - } - } - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } - } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" - } - } - } - } - stage ("Terminate") { - parallel { - stage('Terminate eNB') { - steps { - echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - sh "python3 ci-scripts/main.py --mode=TerminateeNB" - } - post { - success { - script { - termStatusArray[termENB] = true - } - } - } - } - } - } - stage('Log Collection') { - parallel { - stage('Log Collection (eNB - Run)') { - steps { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - 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: ${BUILD_ID}#' -e 's#TEMPLATE_STAGE_NAME#${testStageName}#' test_results-${JOB_NAME}.html" - archiveArtifacts "test_results-${JOB_NAME}.html" - } - } - } - } - } - } - } - - post { - always { - script { - if (params.pipelineZipsConsoleLog != null) { - if (params.pipelineZipsConsoleLog) { - echo "Archiving Jenkins console log" - sh "wget --no-check-certificate --no-proxy ${env.JENKINS_URL}/job/${env.JOB_NAME}/${env.BUILD_ID}/consoleText -O consoleText.log || true" - sh "zip -m consoleText.log.${env.BUILD_ID}.zip consoleText.log || true" - if(fileExists("consoleText.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "consoleText.log.${env.BUILD_ID}.zip" - } - } - } - } - } - // Making sure that we really shutdown every thing before leaving - failure { - script { - if (!termStatusArray[termENB]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB" - } - } - } - } -} diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 71e437676c..be42790a5c 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -209,7 +209,7 @@ def CheckLogs(self, filename, HTML, RAN): elif 'nv-cubb' in name: msg = 'Undeploy PNF/Nvidia CUBB' HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK) - elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb'])): + elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb','vnf'])): logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m') logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers) opt = f"xNB log analysis ({name})" diff --git a/cmake_targets/snap_environment.sh b/cmake_targets/snap_environment.sh deleted file mode 100755 index 1c0725d8b5..0000000000 --- a/cmake_targets/snap_environment.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -export UHD_IMAGES_DIR=$SNAP/uhd_images -exec $@ diff --git a/cmake_targets/tools/Kbuild.cmake b/cmake_targets/tools/Kbuild.cmake deleted file mode 100755 index 7403cd04df..0000000000 --- a/cmake_targets/tools/Kbuild.cmake +++ /dev/null @@ -1,4 +0,0 @@ -src=${dir} -obj-m += ${name}.o -${name}-y += ${objs} -ccflags-y += ${module_cc_opt} diff --git a/cmake_targets/tools/MODULES/CMakeParseArguments.cmake b/cmake_targets/tools/MODULES/CMakeParseArguments.cmake deleted file mode 100755 index ab53b112fa..0000000000 --- a/cmake_targets/tools/MODULES/CMakeParseArguments.cmake +++ /dev/null @@ -1,66 +0,0 @@ -# Analogue for standard CMake module with same name, appeared in CMake 2.8.3. -# -# Used for compatibility with older versions of cmake. - -function(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords) - set(all_keywords ${options} ${one_value_keywords} ${multi_value_keywords}) - # Clear variables before parsing. - foreach(arg ${one_value_keywords} ${multie_value_keywords}) - set(cpa_${arg}) - endforeach() - - foreach(arg ${options}) - set(cpa_${arg} FALSE) - endforeach() - - set(cpa_UNPARSED_ARGUMENTS) - - set(current_keyword) - # Classification for current_keyword: - # 'ONE' or 'MULTY'. - set(current_keyword_type) - - # now iterate over all arguments and fill the result variables - foreach(arg ${ARGN}) - list(FIND all_keywords ${arg} keyword_index) - - if(keyword_index EQUAL -1) - if(current_keyword) - if(current_keyword_type STREQUAL "ONE") - set(cpa_${current_keyword} ${arg}) - set(current_keyword) - else(current_keyword_type STREQUAL "ONE") - list(APPEND cpa_${current_keyword} ${arg}) - endif(current_keyword_type STREQUAL "ONE") - else(current_keyword) - list(APPEND cpa_UNPARSED_ARGUMENTS ${arg}) - endif(current_keyword) - else(keyword_index EQUAL -1) - if(current_keyword AND current_keyword_type STREQUAL "ONE") - message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}") - endif(current_keyword AND current_keyword_type STREQUAL "ONE") - list(FIND options ${arg} option_index) - if(option_index EQUAL -1) - set(current_keyword ${arg}) - list(FIND one_value_keywords ${arg} one_value_index) - if(one_value_index EQUAL -1) - set(current_keyword_type "MULTI") - else(one_value_index EQUAL -1) - set(current_keyword_type "ONE") - endif(one_value_index EQUAL -1) - else(option_index EQUAL -1) - set(current_keyword) - set(cpa_${arg} TRUE) - endif(option_index EQUAL -1) - endif(keyword_index EQUAL -1) - endforeach(arg ${ARGN}) - - if(current_keyword AND current_keyword_type STREQUAL "ONE") - message(SEND_ERROR "Value is expected for one-value-keyword ${current_keyword}") - endif(current_keyword AND current_keyword_type STREQUAL "ONE") - - # propagate the result variables to the caller: - foreach(keyword ${all_keywords} UNPARSED_ARGUMENTS) - set(${prefix}_${keyword} ${cpa_${keyword}} PARENT_SCOPE) - endforeach(keyword ${all_keywords}) -endfunction(cmake_parse_arguments prefix options one_value_keywords multi_value_keywords) diff --git a/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake b/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake deleted file mode 100755 index 1b5de7e3ac..0000000000 --- a/cmake_targets/tools/MODULES/CMakeUserFindMySQL.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# - Find mysqlclient -# Find the native MySQL includes and library -# -# MYSQL_INCLUDE_DIR - where to find mysql.h, etc. -# MYSQL_LIBRARIES - List of libraries when using MySQL. -# MYSQL_FOUND - True if MySQL found. - -IF (MYSQL_INCLUDE_DIR) - # Already in cache, be silent - SET(MYSQL_FIND_QUIETLY TRUE) -ENDIF (MYSQL_INCLUDE_DIR) - -FIND_PATH(MYSQL_INCLUDE_DIR mysql.h - /usr/local/include/mysql - /usr/include/mysql -) - -SET(MYSQL_NAMES mysqlclient mysqlclient_r) -FIND_LIBRARY(MYSQL_LIBRARY - NAMES ${MYSQL_NAMES} - PATHS /usr/lib /usr/local/lib - PATH_SUFFIXES mysql -) - -IF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) - SET(MYSQL_FOUND TRUE) - SET( MYSQL_LIBRARIES ${MYSQL_LIBRARY} ) -ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) - SET(MYSQL_FOUND FALSE) - SET( MYSQL_LIBRARIES ) -ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) - -IF (MYSQL_FOUND) - IF (NOT MYSQL_FIND_QUIETLY) - MESSAGE(STATUS "Found MySQL: ${MYSQL_LIBRARY}") - ENDIF (NOT MYSQL_FIND_QUIETLY) -ELSE (MYSQL_FOUND) - IF (MYSQL_FIND_REQUIRED) - MESSAGE(STATUS "Looked for MySQL libraries named ${MYSQL_NAMES}.") - MESSAGE(FATAL_ERROR "Could NOT find MySQL library") - ENDIF (MYSQL_FIND_REQUIRED) -ENDIF (MYSQL_FOUND) - -MARK_AS_ADVANCED( - MYSQL_LIBRARY - MYSQL_INCLUDE_DIR - ) - diff --git a/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake b/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake deleted file mode 100755 index 5295a1ba39..0000000000 --- a/cmake_targets/tools/MODULES/CMakeUserUseBison.cmake +++ /dev/null @@ -1,71 +0,0 @@ -# - Look for GNU Bison, the parser generator -# Based off a news post from Andy Cedilnik at Kitware -# Defines the following: -# BISON_EXECUTABLE - path to the bison executable -# BISON_FILE - parse a file with bison -# BISON_PREFIX_OUTPUTS - Set to true to make BISON_FILE produce prefixed -# symbols in the generated output based on filename. -# So for ${filename}.y, you'll get ${filename}parse(), etc. -# instead of yyparse(). -# BISON_GENERATE_DEFINES - Set to true to make BISON_FILE output the matching -# .h file for a .c file. You want this if you're using -# flex. - -IF(NOT DEFINED BISON_PREFIX_OUTPUTS) - SET(BISON_PREFIX_OUTPUTS FALSE) -ENDIF(NOT DEFINED BISON_PREFIX_OUTPUTS) - -IF(NOT DEFINED BISON_GENERATE_DEFINES) - SET(BISON_GENERATE_DEFINES FALSE) -ENDIF(NOT DEFINED BISON_GENERATE_DEFINES) - -IF(NOT BISON_EXECUTABLE) - MESSAGE(STATUS "Looking for bison") - FIND_PROGRAM(BISON_EXECUTABLE bison) - IF(BISON_EXECUTABLE) - MESSAGE(STATUS "Looking for bison -- ${BISON_EXECUTABLE}") - ENDIF(BISON_EXECUTABLE) -ENDIF(NOT BISON_EXECUTABLE) - -IF(BISON_EXECUTABLE) - MACRO(BISON_FILE FILENAME) - GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH) - IF("${PATH}" STREQUAL "") - SET(PATH_OPT "") - ELSE("${PATH}" STREQUAL "") - SET(PATH_OPT "/${PATH}") - ENDIF("${PATH}" STREQUAL "") - GET_FILENAME_COMPONENT(HEAD "${FILENAME}" NAME_WE) - IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - IF(BISON_PREFIX_OUTPUTS) - SET(PREFIX "${HEAD}") - ELSE(BISON_PREFIX_OUTPUTS) - SET(PREFIX "yy") - ENDIF(BISON_PREFIX_OUTPUTS) - SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.c") - IF(BISON_GENERATE_DEFINES) - SET(HEADER "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/${HEAD}.tab.h") - ADD_CUSTOM_COMMAND( - OUTPUT "${OUTFILE}" "${HEADER}" - COMMAND "${BISON_EXECUTABLE}" - ARGS "--name-prefix=${PREFIX}" - "--defines" - "--output-file=${OUTFILE}" - "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") - SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" "${HEADER}" PROPERTIES GENERATED TRUE) - SET_SOURCE_FILES_PROPERTIES("${HEADER}" PROPERTIES HEADER_FILE_ONLY TRUE) - ELSE(BISON_GENERATE_DEFINES) - ADD_CUSTOM_COMMAND( - OUTPUT "${OUTFILE}" - COMMAND "${BISON_EXECUTABLE}" - ARGS "--name-prefix=${PREFIX}" - "--output-file=${OUTFILE}" - "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") - SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE) - ENDIF(BISON_GENERATE_DEFINES) - ENDMACRO(BISON_FILE) -ENDIF(BISON_EXECUTABLE) diff --git a/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake b/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake deleted file mode 100755 index 09a3e71e6d..0000000000 --- a/cmake_targets/tools/MODULES/CMakeUserUseFlex.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# - Look for GNU flex, the lexer generator. -# Defines the following: -# FLEX_EXECUTABLE - path to the flex executable -# FLEX_FILE - parse a file with flex -# FLEX_PREFIX_OUTPUTS - Set to true to make FLEX_FILE produce outputs of -# lex.${filename}.c, not lex.yy.c . Passes -P to flex. - -IF(NOT DEFINED FLEX_PREFIX_OUTPUTS) - SET(FLEX_PREFIX_OUTPUTS FALSE) -ENDIF(NOT DEFINED FLEX_PREFIX_OUTPUTS) - -IF(NOT FLEX_EXECUTABLE) - MESSAGE(STATUS "Looking for flex") - FIND_PROGRAM(FLEX_EXECUTABLE flex) - IF(FLEX_EXECUTABLE) - MESSAGE(STATUS "Looking for flex -- ${FLEX_EXECUTABLE}") - ENDIF(FLEX_EXECUTABLE) -ENDIF(NOT FLEX_EXECUTABLE) - -IF(FLEX_EXECUTABLE) - MACRO(FLEX_FILE FILENAME) - GET_FILENAME_COMPONENT(PATH "${FILENAME}" PATH) - IF("${PATH}" STREQUAL "") - SET(PATH_OPT "") - ELSE("${PATH}" STREQUAL "") - SET(PATH_OPT "/${PATH}") - ENDIF("${PATH}" STREQUAL "") - IF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - ENDIF(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}") - IF(FLEX_PREFIX_OUTPUTS) - GET_FILENAME_COMPONENT(PREFIX "${FILENAME}" NAME_WE) - ELSE(FLEX_PREFIX_OUTPUTS) - SET(PREFIX "yy") - ENDIF(FLEX_PREFIX_OUTPUTS) - SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}${PATH_OPT}/lex.${PREFIX}.c") - ADD_CUSTOM_COMMAND( - OUTPUT "${OUTFILE}" - COMMAND "${FLEX_EXECUTABLE}" - ARGS "--prefix=${PREFIX}" - "--outfile=${OUTFILE}" - "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}") - SET_SOURCE_FILES_PROPERTIES("${OUTFILE}" PROPERTIES GENERATED TRUE) - ENDMACRO(FLEX_FILE) -ENDIF(FLEX_EXECUTABLE) diff --git a/cmake_targets/tools/MODULES/FindGCCXML.cmake b/cmake_targets/tools/MODULES/FindGCCXML.cmake deleted file mode 100755 index 6a4daa084d..0000000000 --- a/cmake_targets/tools/MODULES/FindGCCXML.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# FindGCCXML -# ---------- -find_program(GCCXML -NAMES gccxml -PATHS "/usr/bin" -"usr/local/bin" -) -mark_as_advanced(GCCXML) diff --git a/cmake_targets/tools/MODULES/FindKbuild.cmake b/cmake_targets/tools/MODULES/FindKbuild.cmake deleted file mode 100755 index 08accb8551..0000000000 --- a/cmake_targets/tools/MODULES/FindKbuild.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# - Support for building kernel modules - -# This module defines several variables which may be used when build -# kernel modules. -# -# The following variables are set here: -# Kbuild_VERSION_STRING - kernel version. -# Kbuild_ARCH - architecture. -# Kbuild_BUILD_DIR - directory for build kernel and/or its components. -# Kbuild_VERSION_{MAJOR|MINOR|TWEAK} - kernel version components -# Kbuild_VERSION_STRING_CLASSIC - classic representation of version, -# where parts are delimited by dots. -# -# Cache variables which affect on this package: -# CMAKE_SYSTEM_VERSION - change Kbuild_VERSION_STRING -# Also, setting CMAKE_SYSTEM_VERSION will be interpreted by cmake as crosscompile. -# -# Cache variables(ADVANCED) which affect on this package: -# ARCH - if not empty, change Kbuild_ARCH -# KBUILD_DIR - change Kbuild_BUILD_DIR - -set(Kbuild_VERSION_STRING ${CMAKE_SYSTEM_VERSION}) - -# Form classic version view. -string(REGEX MATCH "([0-9]+)\\.([0-9]+)[.-]([0-9]+)" - _kernel_version_match - "${Kbuild_VERSION_STRING}" -) - -if(NOT _kernel_version_match) - message(FATAL_ERROR "Kernel version has unexpected format: ${Kbuild_VERSION_STRING}") -endif(NOT _kernel_version_match) - -set(Kbuild_VERSION_MAJOR ${CMAKE_MATCH_1}) -set(Kbuild_VERSION_MINOR ${CMAKE_MATCH_2}) -set(Kbuild_VERSION_TWEAK ${CMAKE_MATCH_3}) -# Version string for compare -set(Kbuild_VERSION_STRING_CLASSIC "${Kbuild_VERSION_MAJOR}.${Kbuild_VERSION_MINOR}.${Kbuild_VERSION_TWEAK}") - -set(KBUILD_DIR "/lib/modules/${Kbuild_VERSION_STRING}/build" CACHE PATH - "Directory for build linux kernel and/or its components." -) -mark_as_advanced(KBUILD_DIR) - -set(Kbuild_BUILD_DIR "${KBUILD_DIR}") - -set(ARCH "" CACHE STRING - "Architecture for build linux kernel components for, empty string means autodetect." -) -mark_as_advanced(ARCH) - -if(NOT ARCH) - # Autodetect arch. - execute_process(COMMAND uname -m - RESULT_VARIABLE uname_m_result - OUTPUT_VARIABLE ARCH_DEFAULT - ) - if(NOT uname_m_result EQUAL 0) - message("'uname -m' failed:") - message("${ARCH_DEFAULT}") - message(FATAL_ERROR "Failed to determine system architecture.") - endif(NOT uname_m_result EQUAL 0) - - string(REGEX REPLACE "\n$" "" ARCH_DEFAULT "${ARCH_DEFAULT}") - - # Pairs of pattern-replace for postprocess architecture string from - # 'uname -m'. - # Taken from ./Makefile of the kernel build. - set(_kbuild_arch_replacers - "i.86" "x86" - "x86_64" "x86" - "sun4u" "sparc64" - "arm.*" "arm" - "sa110" "arm" - "s390x" "s390" - "parisc64" "parisc" - "ppc.*" "powerpc" - "mips.*" "mips" - "sh[234].*" "sh" - "aarch64.*" "arm64" - ) - - set(_current_pattern) - foreach(p ${_kbuild_arch_replacers}) - if(_current_pattern) - string(REGEX REPLACE "${_current_pattern}" "${p}" ARCH_DEFAULT "${ARCH_DEFAULT}") - set(_current_pattern) - else(_current_pattern) - set(_current_pattern "${p}") - endif(_current_pattern) - endforeach(p ${_kbuild_arch_replacers}) - - set(Kbuild_ARCH "${ARCH_DEFAULT}") -else(NOT ARCH) - # User-provided value is used. - set(Kbuild_ARCH "${ARCH}") -endif(NOT ARCH) - - - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Kbuild - REQUIRED_VARS Kbuild_BUILD_DIR - VERSION_VAR KBuild_VERSION_STRING_CLASSIC -) diff --git a/cmake_targets/tools/MODULES/Kbuild.cmake b/cmake_targets/tools/MODULES/Kbuild.cmake deleted file mode 100755 index 7403cd04df..0000000000 --- a/cmake_targets/tools/MODULES/Kbuild.cmake +++ /dev/null @@ -1,4 +0,0 @@ -src=${dir} -obj-m += ${name}.o -${name}-y += ${objs} -ccflags-y += ${module_cc_opt} diff --git a/cmake_targets/tools/MODULES/cmake_useful.cmake b/cmake_targets/tools/MODULES/cmake_useful.cmake deleted file mode 100755 index af6bbb56c7..0000000000 --- a/cmake_targets/tools/MODULES/cmake_useful.cmake +++ /dev/null @@ -1,229 +0,0 @@ -# Create rule for obtain one file by copying another one -function(rule_copy_file target_file source_file) - add_custom_command(OUTPUT ${target_file} - COMMAND cp -p ${source_file} ${target_file} - DEPENDS ${source_file} - ) -endfunction(rule_copy_file target_file source_file) - -# rule_copy_source([source_dir] file ...) -# -# Create rule for obtain file(s) in binary tree by copiing it from source tree. -# -# Files are given relative to ${source_dir}, if it is set, or -# relative to ${CMAKE_CURRENT_SOURCE_DIR}. -# -# Files will be copied into ${CMAKE_CURRENT_BINARY_DIR} with same -# relative paths. -# -# ${source_dir} should be absolute path(that is, starts from '/'). -# Otherwise first argument is treated as first file to copy. -function(rule_copy_source file) - string(REGEX MATCH "^/" is_abs_path ${file}) - if(is_abs_path) - set(source_dir ${file}) - set(files ${ARGN}) - else(is_abs_path) - set(source_dir ${CMAKE_CURRENT_SOURCE_DIR}) - set(files ${file} ${ARGN}) - endif(is_abs_path) - - foreach(file_real ${files}) - rule_copy_file("${CMAKE_CURRENT_BINARY_DIR}/${file_real}" - ${source_dir}/${file_real}) - endforeach(file_real ${files}) -endfunction(rule_copy_source file) - -# to_abs_path(output_var path [...]) -# -# Convert relative path of file to absolute path: -# use path in source tree, if file already exist there. -# otherwise use path in binary tree. -# If initial path already absolute, return it. -function(to_abs_path output_var) - set(result) - foreach(path ${ARGN}) - string(REGEX MATCH "^/" _is_abs_path ${path}) - if(_is_abs_path) - list(APPEND result ${path}) - else(_is_abs_path) - file(GLOB to_abs_path_file - "${CMAKE_CURRENT_SOURCE_DIR}/${path}" - ) - if(NOT to_abs_path_file) - set (to_abs_path_file "${CMAKE_CURRENT_BINARY_DIR}/${path}") - endif(NOT to_abs_path_file) - list(APPEND result ${to_abs_path_file}) - endif(_is_abs_path) - endforeach(path ${ARGN}) - set("${output_var}" ${result} PARENT_SCOPE) -endfunction(to_abs_path output_var path) - -# is_path_inside_dir(output_var dir path) -# -# Set output_var to true if path is absolute path inside given directory. -# NOTE: Path should be absolute. -macro(is_path_inside_dir output_var dir path) - file(RELATIVE_PATH _rel_path ${dir} ${path}) - string(REGEX MATCH "^\\.\\." _is_not_inside_dir ${_rel_path}) - if(_is_not_inside_dir) - set(${output_var} "FALSE") - else(_is_not_inside_dir) - set(${output_var} "TRUE") - endif(_is_not_inside_dir) -endmacro(is_path_inside_dir output_var dir path) - - -# Write given content to the file. -# -# If file is already exists and its content is same as written one, file -# is not rewritten, so its write timestamp remains unchanged. -function(file_update filename content) - if(EXISTS "${filename}") - file(READ "${filename}" old_content) - if(old_content STREQUAL "${content}") - return() - endif(old_content STREQUAL "${content}") - endif(EXISTS "${filename}") - # File doesn't exists or its content differ. - file(WRITE "${filename}" "${content}") -endfunction(file_update filename content) - - -# Write given content to the file in APPEND mode. -# -# For append we use position variable which should be initialized -# to 0 for every new build process and which is updated every time when -# this function is called. -# If file is already exists and its content at given is same as -# written one, file is not rewritten, so its write timestamp remains unchanged. -# -# Note, that file will not be rewritten if new build process issues less -# APPEND actions than one which create file. -# But similar problem exists for file_update() and even for built-in -# configure_file() command: file will not be removed if new build process -# do not call configure_file() for it. -function(file_update_append filename content POS) - set(pos "${${POS}}") - string(LENGTH "${content}" len) - # Update output variable first. - # This allows to use return() when need not to do anything - math(EXPR pos_new "${pos}+${len}") - set(${POS} "${pos_new}" PARENT_SCOPE) - if(EXISTS "${filename}") - file(READ "${filename}" old_content LIMIT "${len}" OFFSET "${pos}") - if(old_content STREQUAL "${content}") - return() - elseif(old_content STREQUAL "") - file(APPEND "${filename}" "${content}") - return() - endif(old_content STREQUAL "${content}") - else(EXISTS "${filename}") - if(NOT pos EQUAL 0) - message(FATAL_ERROR "Appending to non-zero position to non-existent file.") - endif(NOT pos EQUAL 0) - endif(EXISTS "${filename}") - # File doesn't exists or its content differ. - if(NOT pos EQUAL 0) - file(READ "${filename}" prefix LIMIT "${pos}") - else(NOT pos EQUAL 0) - set(prefix) - endif(NOT pos EQUAL 0) - file(WRITE "${filename}" "${prefix}${content}") -endfunction(file_update_append filename content POS) - - -# Common mechanism for output status message -# when checking different aspects. -# -# Normal using: -# -# check_begin("Checking <...>") -# if(NOT ) -# check_try() # Here message is printed -# # Perform check(try_compile(), etc.) -# endif(NOT ) -# check_end("") # Here message is printed with result. - -# Should be called (unconditionally) when new cheking is issued. -# Note, that given @status_msg is not printed at that step. -function(check_begin status_msg) - set(_check_status_msg ${status_msg} PARENT_SCOPE) - set(_check_has_tries PARENT_SCOPE) -endfunction(check_begin status_msg) - -# Should be called before every real checking, that is which is not come -# from cache variables comparision. -# -# First call of that function is trigger printing of @status_msg, -# passed to check_begin(). -function(check_try) - if(NOT _check_has_tries) - message(STATUS "${_check_status_msg}") - set(_check_has_tries "1" PARENT_SCOPE) - endif(NOT _check_has_tries) -endfunction(check_try) - -# Should be called when cheking is end, and @result_msg should be short -# description of check result. -# If any check_try() has been issued before, -# "@status_msg - @result_msg" -# will be printed. -# Otherwise, -# "@status_msg - [cached] @result_msg" -# will be printed, at it will be the only message for that check. -function(check_end result_msg) - if(NOT _check_has_tries) - message(STATUS "${_check_status_msg} [cached] - ${result_msg}") - else(NOT _check_has_tries) - message(STATUS "${_check_status_msg} - ${result_msg}") - endif(NOT _check_has_tries) - set(_check_status_msg PARENT_SCOPE) - set(_check_has_tries PARENT_SCOPE) -endfunction(check_end result_msg) - -# set_bool_string(var true_string false_string value [CACHE ... | PARENT_SCOPE]) -# -# Set variable to one of two string according to true property of some value. -# -# If 'value' is true-evaluated, 'var' will be set to 'true_string', -# otherwise to 'var' will be set to 'false_string'. -# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers. -# -# Useful for form meaningful value for cache variables, contained result -# of some operation. -# Also may be used for form message for check_end(). -macro(set_bool_string var true_string false_string value) - # Macro parameters are not a variables, so them cannot be tested - # using 'if(value)'. - # Usage 'if(${value})' leads to warnings since 2.6.4 when ${val} - # is boolean constant - # (because until 2.6.4 'if(value)' always dereference val). - # So copy 'value' to local variable for test it. - set(_set_bool_string_value ${value}) - if(_set_bool_string_value) - set(${var} "${true_string}" ${ARGN}) - else() - set(${var} "${false_string}" ${ARGN}) - endif() -endmacro(set_bool_string) - -# set_zero_string(var true_string false_string value [CACHE ... | PARENT_SCOPE]) -# -# Set variable to one of two string according to zero property of some value. -# -# If 'value' is '0' (presizely), 'var' will be set to 'zero_string', -# otherwise to 'var' will be set to 'nonzero_string'. -# Like standard set(), macro accept CACHE and PARENT_SCOPE modifiers. -# -# Useful for form meaningful value for cache variables, contained result -# of execute_process(). -# Also may be used for form message for check_end(). -macro(set_zero_string var zero_string nonzero_string value) - set(_set_zero_string_value ${value}) - if(_set_zero_string_value EQUAL "0") - set(${var} ${zero_string} ${ARGN}) - else() - set(${var} ${nonzero_string} ${ARGN}) - endif() -endmacro(set_zero_string) \ No newline at end of file diff --git a/cmake_targets/tools/MODULES/kbuild_system.cmake b/cmake_targets/tools/MODULES/kbuild_system.cmake deleted file mode 100755 index 42a1a2d42b..0000000000 --- a/cmake_targets/tools/MODULES/kbuild_system.cmake +++ /dev/null @@ -1,1131 +0,0 @@ -# Provide way for create kernel modules, and perform other actions on them -# in a way similar to standard cmake executables and libraries processing. -# -# NB: At the end of the whole configuration stage -# kbuild_finalize_linking() -# should be executed. -# -# Should be included after: -# find_package(Kbuild) -# -# Cached variables(ADVANCED), which affects on definitions below: -# CROSS_COMPILE - corresponded parameter for 'make' to build kernel objects. -# KBUILD_C_FLAGS - Additional kbuild flags for all builds -# KBUILD_C_FLAGS{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL} - per-configuration flags. - -include(cmake_useful) - -# Compute path to the auxiliary files. -get_filename_component(kbuild_this_module_dir ${CMAKE_CURRENT_LIST_FILE} PATH) -set(kbuild_aux_dir "${kbuild_this_module_dir}/kbuild_system_files") - -# _declare_per_build_vars( ) -# -# [INTERNAL] Per-build type definitions for given . -# -# Create CACHE STRING variables _{DEBUG|RELEASE|RELWITHDEBINFO|MINSIZEREL} -# with documentation string where %build% is replaced -# with corresponded build type description. -# -# Default value for variable _ is taken from __INIT. -macro(_declare_per_build_vars variable doc_pattern) - set(_build_type) - foreach(t - RELEASE "release" - DEBUG "debug" - RELWITHDEBINFO "Release With Debug Info" - MINSIZEREL "release minsize" - ) - if(_build_type) - string(REPLACE "%build%" "${t}" _docstring ${doc_pattern}) - set("${variable}_${_build_type}" "${${variable}_${_build_type}_INIT}" - CACHE STRING "${_docstring}") - set(_build_type) - else(_build_type) - set(_build_type "${t}") - endif(_build_type) - endforeach(t) -endmacro(_declare_per_build_vars variable doc_pattern) - - -# Default compiler flags. -# -# These flags are used directly when configuring 'Kbuild', so them should be -# expressed as single-string, where different flags are joinged using ' '. -set(KBUILD_C_FLAGS "" CACHE STRING - "Compiler flags used by Kbuild system during all builds." -) - -# Additional default compiler flags per build type. -set(KBUILD_C_FLAGS_DEBUG_INIT "-g") -set(KBUILD_C_FLAGS_RELWITHDEBINFO_INIT "-g") - -_declare_per_build_vars(KBUILD_C_FLAGS - "Compiler flags used by Kbuild system during %build% builds." -) -mark_as_advanced( - KBUILD_C_FLAGS - KBUILD_C_FLAGS_DEBUG - KBUILD_C_FLAGS_RELEASE - KBUILD_C_FLAGS_RELWITHDEBINFO - KBUILD_C_FLAGS_MINSIZEREL -) - - -# Additional definitions which are passed directly to 'make' for -# kbuild process. -# -# Unlike to compiler flags, these ones are expressed using cmake list. -set(KBUILD_MAKE_FLAGS "" CACHE STRING - "Make flags used by Kbuild system during all builds." -) - -_declare_per_build_vars(KBUILD_MAKE_FLAGS - "Make flags used by Kbuild system during %build% builds." -) - -mark_as_advanced( - KBUILD_MAKE_FLAGS - KBUILD_MAKE_FLAGS_DEBUG - KBUILD_MAKE_FLAGS_RELEASE - KBUILD_MAKE_FLAGS_RELWITHDEBINFO - KBUILD_MAKE_FLAGS_MINSIZEREL -) - -set(CROSS_COMPILE "" CACHE STRING "Cross compilation prefix for build linux kernel objects.") -mark_as_advanced(CROSS_COMPILE) - -# Property prefixed with 'KMODULE_' is readonly for outer use, -# unless explicitely noted in its description. - -# Property is set for every target described kernel module. -# Concrete property's value currently has no special meaning. -define_property(TARGET PROPERTY KMODULE_TYPE - BRIEF_DOCS "Whether given target describes kernel module." - FULL_DOCS "Whether given target describes kernel module." -) - -# Absolute filename of .ko file which is built. -# NOTE: Imported targets use -# KMODULE_IMPORTED_MODULE_LOCATION -# property instead. -define_property(TARGET PROPERTY KMODULE_MODULE_LOCATION - BRIEF_DOCS "Location of the built kernel module." - FULL_DOCS "Location of the built kernel module." -) - -# Name of the given module, like "ext4" or "kedr". -define_property(TARGET PROPERTY KMODULE_MODULE_NAME - BRIEF_DOCS "Name of the kernel module." - FULL_DOCS "Name of the kernel module." -) - - -# Absolute filename of Module.symvers file which is built. -# NOTE: Imported targets use -# KMODULE_IMPORTED_SYMVERS_LOCATION -# property instead. -define_property(TARGET PROPERTY KMODULE_SYMVERS_LOCATION - BRIEF_DOCS "Location of the symvers file of the kernel module." - FULL_DOCS "Location of the symvers file of the kernel module." -) - -# Property is "TRUE" for every target described imported kernel module, -# "FALSE" for other targets described kernel module. -define_property(TARGET PROPERTY KMODULE_IMPORTED - BRIEF_DOCS "Whether given target describes imported kernel module." - FULL_DOCS "Whether given target describes imported kernel module." -) - -# Absolute filename of .ko file which is imported. -# Property may be set after -# kbuild_add_module(... IMPORTED) -# for allow loading of given module or perform other actions required -# kernel module itself. -# -# Analogue for KMODULE_MODULE_LOCATION property of normal(non-exported) -# kernel module target. -define_property(TARGET PROPERTY KMODULE_IMPORTED_MODULE_LOCATION - BRIEF_DOCS "Location of the imported kernel module." - FULL_DOCS "Location of the imported kernel module." -) - -# Absolute filename of Module.symvers file for imported kernel module. -# Property may be set after -# kbuild_add_module(... IMPORTED) -# for allow linking with given module or perform other actions required -# its symbols. -# -# Analogue for KMODULE_MODULE_SYMVERS_LOCATION property of normal(non-exported) -# kernel module target. -define_property(TARGET PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION - BRIEF_DOCS "Location of the symvers file for imported kernel module." - FULL_DOCS "Location of the symvers file for imported kernel module." -) - -# Helpers for simple extract some kernel module properties. - -# kbuild_get_module_location(RESULT_VAR name) -# -# Return location of the module, determined by the property -# KMODULE_MODULE_LOCATION or KMODULE_IMPORTED_MODULE_LOCATION for -# imported target. In the last case the property is checked for being set. -function(kbuild_get_module_location RESULT_VAR name) - if(NOT TARGET ${name}) - message(FATAL_ERROR "\"${name}\" is not really a target.") - endif(NOT TARGET ${name}) - get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE) - if(NOT kmodule_type) - message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.") - endif(NOT kmodule_type) - get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) - if(kmodule_imported) - get_property(module_location TARGET ${name} PROPERTY KMODULE_IMPORTED_MODULE_LOCATION) - if(NOT module_location) - message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_MODULE_LOCATION set.") - endif(NOT module_location) - else(kmodule_imported) - get_property(module_location TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION) - endif(kmodule_imported) - set(${RESULT_VAR} ${module_location} PARENT_SCOPE) -endfunction(kbuild_get_module_location RESULT_VAR module) - -# kbuild_get_symvers_location(RESULT_VAR name) -# -# Return location of the symvers file for the module, determined by the -# property KMODULE_SYMVERS_LOCATION or KMODULE_IMPORTED_SYMVERS_LOCATION -# for imported target. In the last case the property is checked for being set. -function(kbuild_get_symvers_location RESULT_VAR name) - if(NOT TARGET ${name}) - message(FATAL_ERROR "\"${name}\" is not really a target.") - endif(NOT TARGET ${name}) - get_property(kmodule_type TARGET ${name} PROPERTY KMODULE_TYPE) - if(NOT kmodule_type) - message(FATAL_ERROR "\"${name}\" is not really a target for kernel module.") - endif(NOT kmodule_type) - get_property(kmodule_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) - if(kmodule_imported) - get_property(symvers_location TARGET ${name} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION) - if(NOT symvers_location) - message(FATAL_ERROR "target \"${name}\" for imported module has no property KMODULE_IMPORTED_SYMVERS_LOCATION set.") - endif(NOT symvers_location) - else(kmodule_imported) - get_property(symvers_location TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION) - endif(kmodule_imported) - set(${RESULT_VAR} ${symvers_location} PARENT_SCOPE) -endfunction(kbuild_get_symvers_location RESULT_VAR module) - -# kbuild_add_module( [EXCLUDE_FROM_ALL] [MODULE_NAME ] [ ...]) -# -# Build kernel module from , analogue of add_library(). -# -# Source files are divided into two categories: -# -Object sources -# -Other sourses -# -# Object sources are those sources, which may be used in building kernel -# module externally. -# Follow types of object sources are supported now: -# .c: a file with the code in C language; -# .S: a file with the code in assembly language; -# .o_shipped: shipped file in binary format, -# does not require additional preprocessing. -# -# Other sources are treated as only prerequisite of building process. -# -# -# kbuild_add_module( [MODULE_NAME ] IMPORTED) -# -# Create target, corresponded to the imported kernel module. -# In that case KMODULE_IMPORTED_* properties should be set manually if needed. -# -# In either case, if MODULE_NAME option is given, it determine name -# of the kernel module. Otherwise itself is used. -function(kbuild_add_module name) - cmake_parse_arguments(kbuild_add_module "IMPORTED;EXCLUDE_FROM_ALL" "MODULE_NAME" "" ${ARGN}) - if(kbuild_add_module_MODULE_NAME) - set(module_name "${kbuild_add_module_MODULE_NAME}") - else(kbuild_add_module_MODULE_NAME) - set(module_name "${name}") - endif(kbuild_add_module_MODULE_NAME) - - string(LENGTH ${module_name} module_name_len) - if(module_name_len GREATER 55) - # Name of the kernel module should fit into array of size (64-sizeof(unsigned long)). - # On 64-bit systems(most restricted) this is 56. - # Even 56 length is not good, as it is not include null character. - # Without it, old versions of rmmod failed to unload module. - message(SEND_ERROR "Kernel module name exceeds 55 characters: '${module_name}'") - endif(module_name_len GREATER 55) - - if(kbuild_add_module_IMPORTED) - # Creation of IMPORTED target is simple. - add_custom_target(${name}) - set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule") - set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "TRUE") - set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}") - return() - endif(kbuild_add_module_IMPORTED) - - if(kbuild_add_module_EXCLUDE_FROM_ALL) - set(all_arg) - else(kbuild_add_module_EXCLUDE_FROM_ALL) - set(all_arg "ALL") - endif(kbuild_add_module_EXCLUDE_FROM_ALL) - - # List of all source files, which are given. - set(sources ${kbuild_add_module_UNPARSED_ARGUMENTS}) - - # Sources with absolute paths - to_abs_path(sources_abs ${sources}) - # list of files from which module building is depended - set(depend_files) - # Sources of "c" type, but without extension. - # Used for clean files, and for out-of-source builds do not create - # files in source tree. - set(c_sources_noext_abs) - # The sources with the code in assembly - set(asm_sources_noext_abs) - # Sources of "o_shipped" type, but without extension - set(shipped_sources_noext_abs) - # Categorize sources - foreach(source_abs ${sources_abs}) - get_filename_component(ext ${source_abs} EXT) - if(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped") - # Real sources - # Move source into binary tree, if needed - copy_source_to_binary_dir("${source_abs}" source_abs) - - get_filename_component(source_noext "${source_abs}" NAME_WE) - get_filename_component(source_dir "${source_abs}" PATH) - set(source_noext_abs "${source_dir}/${source_noext}") - if(ext STREQUAL ".c") - # c-source - list(APPEND c_sources_noext_abs ${source_noext_abs}) - elseif(ext STREQUAL ".S") - # asm source - list(APPEND asm_sources_noext_abs ${source_noext_abs}) - elseif(ext STREQUAL ".o_shipped") - # shipped-source - list(APPEND shipped_sources_noext_abs ${source_noext_abs}) - endif(ext STREQUAL ".c") - endif(ext STREQUAL ".c" OR ext STREQUAL ".S" OR ext STREQUAL ".o_shipped") - # In any case, add file to depend list - list(APPEND depend_files ${source_abs}) - endforeach(source_abs ${sources_abs}) - - # Object sources relative to current binary dir - # (for $(module)-y :=) - set(obj_sources_noext_rel) - foreach(obj_sources_noext_abs - ${c_sources_noext_abs} ${asm_sources_noext_abs} ${shipped_sources_noext_abs}) - file(RELATIVE_PATH obj_source_noext_rel - ${CMAKE_CURRENT_BINARY_DIR} ${obj_sources_noext_abs}) - list(APPEND obj_sources_noext_rel ${obj_source_noext_rel}) - endforeach(obj_sources_noext_abs) - - if(NOT obj_sources_noext_rel) - message(FATAL_ERROR "List of object files for building kernel module ${name} is empty.") - endif(NOT obj_sources_noext_rel) - - set(obj_sources_rel) - # Detect, if build simple - source object name coincide with module name - - if(NOT obj_sources_noext_rel STREQUAL ${name}) - # Check, whether only one of source object names coincide with module name. - # This situation is incorrect for kbuild system. - list(FIND obj_sources_noext_rel ${name} is_objects_contain_name) - if(is_objects_contain_name GREATER -1) - message(FATAL_ERROR "Module should be built " - "either from only one object with same name, " - "or from objects with names different from the name of the module") - endif(is_objects_contain_name GREATER -1) - - foreach(obj_source_noext_rel ${obj_sources_noext_rel}) - list(APPEND obj_sources_rel "${obj_source_noext_rel}.o") - endforeach(obj_source_noext_rel ${obj_sources_noext_rel}) - endif(NOT obj_sources_noext_rel STREQUAL ${name}) - - _get_directory_property_chained(ccflags KBUILD_COMPILE_DEFINITIONS " ") - _get_directory_property_chained(include_dirs KBUILD_INCLUDE_DIRECTORIES) - - # Target for create module. - add_custom_target(${name} ALL - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" - "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" - ) - - # Create .cmd files for 'shipped' sources. - # Gcc does not create them automatically for some reason. - set(cmd_create_command) - if(shipped_sources_noext_abs) - foreach(shipped_source_noext_abs ${shipped_source_noext_abs}) - get_filename_component(shipped_dir ${shipped_source_noext_abs} PATH) - get_filename_component(shipped_name ${shipped_source_noext_abs} NAME) - list(APPEND cmd_create_command - COMMAND printf "cmd_%s.o := cp -p %s.o_shipped %s.o\\n" - "${shipped_source_noext_abs}" - "${shipped_source_noext_abs}" - "${shipped_source_noext_abs}" - > "${shipped_dir}/.${shipped_name}.o.cmd") - endforeach(shipped_source_noext_abs ${shipped_source_noext_abs}) - endif(shipped_sources_noext_abs) - - # User-defined parameters for 'make' - set(make_flags ${KBUILD_MAKE_FLAGS}) - _get_per_build_var(make_flags_per_build KBUILD_MAKE_FLAGS) - list(APPEND make_flags ${make_flags_per_build}) - - # Rule for create module(and symvers file). - add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" - "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" - ${cmd_create_command} - COMMAND $(MAKE) ${make_flags} ${kbuild_additional_make_flags} - -C ${Kbuild_BUILD_DIR} M=${CMAKE_CURRENT_BINARY_DIR} modules -# Update timestamps for targets. -# In some cases Kbuild system may decide do not update resulted files -# even in case when depencies newer. -# Updating timestamps prevent command to be executed every make call. - COMMAND touch "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" - "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" - DEPENDS ${depend_files} - "${CMAKE_CURRENT_BINARY_DIR}/Kbuild" - COMMENT "Building kernel module ${name}" - ) - - # Fill properties for the target. - set_property(TARGET ${name} PROPERTY KMODULE_TYPE "kmodule") - set_property(TARGET ${name} PROPERTY KMODULE_IMPORTED "FALSE") - set_property(TARGET ${name} PROPERTY KMODULE_MODULE_NAME "${module_name}") - - set_property(TARGET ${name} PROPERTY KMODULE_MODULE_LOCATION - "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" - ) - set_property(TARGET ${name} PROPERTY KMODULE_SYMVERS_LOCATION - "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" - ) - - # Internal properties - set_property(TARGET ${name} PROPERTY KMODULE_BINARY_DIR - "${CMAKE_CURRENT_BINARY_DIR}" - ) - set_property(TARGET ${name} PROPERTY KMODULE_OBJ_SOURCES ${obj_sources_rel}) - set_property(TARGET ${name} PROPERTY KMODULE_COMPILE_FLAGS ${ccflags}) - set_property(TARGET ${name} PROPERTY KMODULE_INCLUDE_DIRECTORIES ${include_dirs}) - - - # Add target to the list of modules for built. - set_property(GLOBAL APPEND PROPERTY KMODULE_TARGETS "${name}") - - # The rule to clean files - _kbuild_module_clean_files(${name} - C_SOURCE ${c_sources_noext_abs} - ASM_SOURCE ${asm_sources_noext_abs} - SHIPPED_SOURCE ${shipped_sources_noext_abs}) -endfunction(kbuild_add_module name) - -# kbuild_include_directories(dirs ...) -# -# Add include directories for Kbuild process. -macro(kbuild_include_directories) - set_property(DIRECTORY APPEND PROPERTY KBUILD_INCLUDE_DIRECTORIES ${ARGN}) -endmacro(kbuild_include_directories) - -# kbuild_add_definitions (flags) -# -# Specify additional flags for compile kernel module. -# -# Note that multiple flags should be specified as single string, -# delimited with ' '. -function(kbuild_add_definitions flags) - get_property(current_flags DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS) - _string_join(" " current_flags "${current_flags}" "${flags}") - set_property(DIRECTORY PROPERTY KBUILD_COMPILE_DEFINITIONS "${current_flags}") -endfunction(kbuild_add_definitions flags) - -# There is no control for kbuild make flags except default values. -# Support for kbuild_add_make_definitions may be added if needed. - - -# kbuild_link_module( [ ...]) -# -# Link kernel module with other modules, that allows to use symbols from -# other modules. -# -# may be: -# 1) target name for other kernel module intended for build -# 2) target name for imported kernel module with -# KMODULE_IMPORTED_SYMVERS_LOCATION property set -# 3) absolute path to symvers file of other kernel module. -# -# In any case, file-level dependency will be created for symvers file to link with. -# In the first case, also target-level dependency will be added -# -# Analogue for target_link_library(). -# -# May be used only from the same directory, where module target is created. -function(kbuild_link_module name) - # Check that @name corresponds to kernel module target for build. - get_property(is_module TARGET ${name} PROPERTY KMODULE_TYPE SET) - if(NOT is_module) - message(FATAL_ERROR "kbuild_module_link: passed \n\t\"${name}\"\n which is not kernel module target.") - endif(NOT is_module) - get_property(module_imported TARGET ${name} PROPERTY KMODULE_IMPORTED) - if(kmodule_imported) - message(FATAL_ERROR "Imported kernel module target \"${name}\" may not be linked.") - endif(kmodule_imported) - - get_property(module_name TARGET ${name} PROPERTY KMODULE_MODULE_NAME) - - foreach(l ${ARGN}) - string(REGEX MATCH "/" link_is_file ${l}) - if(link_is_file) - string(REGEX MATCH "^/" file_is_absolute ${l}) - if(NOT file_is_absolute) - message(FATAL_ERROR "kbuild_module_link: passed filename\n\t\"${link}\"\nwhich is not absolute as .") - endif(NOT file_is_absolute) - set(symvers_location "${l}") - # Do not require symvers file to be already existed. - else(link_is_file) - if(NOT TARGET ${l}) - message(FATAL_ERROR "kbuild_module_link: passed link\n\t\"${l}\"\n which is neither an absolute path to symvers file nor a target.") - endif(NOT TARGET ${l}) - get_property(kmodule_type TARGET ${l} PROPERTY KMODULE_TYPE) - if(NOT kmodule_type) - message(FATAL_ERROR "kbuild_module_link: passed target\n\t\"${l}\"\n which is not a target for kernel module as link.") - endif(NOT kmodule_type) - get_property(kmodule_imported TARGET ${l} PROPERTY KMODULE_IMPORTED) - if(kmodule_imported) - get_property(symvers_location TARGET ${l} PROPERTY KMODULE_IMPORTED_SYMVERS_LOCATION) - if(NOT symvers_location) - message(FATAL_ERROR "kbuild_module_link: passed imported target\n\t\"${l}\"\n without \"KMODULE_IMPORTED_SYMVERS_LOCATION\" property set as link.") - endif(NOT symvers_location) - else(kmodule_imported) - get_property(symvers_location TARGET ${l} PROPERTY KMODULE_SYMVERS_LOCATION) - # Target dependency is added only for non-imported target. - add_dependencies(${name} ${l}) - endif(kmodule_imported) - endif(link_is_file) - add_custom_command(OUTPUT - "${CMAKE_CURRENT_BINARY_DIR}/${module_name}.ko" - "${CMAKE_CURRENT_BINARY_DIR}/${_kbuild_symvers}" - DEPENDS ${symvers_location} - APPEND - ) - set_property(TARGET ${name} APPEND PROPERTY KMODULE_DEPEND_SYMVERS ${symvers_location}) - endforeach(l ${ARGN}) -endfunction(kbuild_link_module name) - -# kbuild_finalize_linking() -# -# Should be called after all kernel modules and their links defined. -# Usually this is the end of main CMakeLists.txt file. -function(kbuild_finalize_linking) - _get_per_build_var(ccflags_per_build KBUILD_C_FLAGS) - - get_property(kmodule_targets GLOBAL PROPERTY KMODULE_TARGETS) - foreach(m ${kmodule_targets}) - get_property(module_binary_dir TARGET ${m} PROPERTY KMODULE_BINARY_DIR) - get_property(module_name TARGET ${m} PROPERTY KMODULE_MODULE_NAME) - get_property(module_symvers_cmake TARGET ${m} PROPERTY KMODULE_DEPEND_SYMVERS) - - get_property(obj_sources TARGET ${m} PROPERTY KMODULE_OBJ_SOURCES) - get_property(ccflags_local TARGET ${m} PROPERTY KMODULE_COMPILE_FLAGS) - get_property(include_dirs TARGET ${m} PROPERTY KMODULE_INCLUDE_DIRECTORIES) - - # Combine all compiler flags together - _string_join(" " ccflags "${KBUILD_C_FLAGS}" "${ccflags_local}") - foreach(dir ${include_dirs}) - _string_join(" " ccflags "${ccflags}" "-I${dir}") - endforeach(dir ${include_dirs}) - _string_join(" " ccflags "${ccflags}" "${ccflags_per_build}") - - string(REPLACE ";" " " module_symvers "${module_symvers_cmake}") - - if(obj_sources) - set(obj_src_string "${module_name}-y := ") - foreach(obj ${obj_sources}) - set(obj_src_string "${obj_src_string} ${obj}") - endforeach(obj ${obj_sources}) - else(obj_sources) - # Simple building process - module name is same as the name - # of the only source. - set(obj_src_string "") - endif(obj_sources) - # Configure kbuild file - configure_file(${kbuild_this_module_dir}/kbuild_system_files/Kbuild.in - ${module_binary_dir}/Kbuild - ) - endforeach(m ${kmodule_targets}) -endfunction(kbuild_finalize_linking) - -# kbuild_install(TARGETS ... -# [[MODULE|SYMVERS] -# DESTINATION -# [CONFIGURATIONS [...]] -# [COMPONENT ] -# ]+) -# -# Install kernel module(s) and/or symvers file(s) into given directory. -# -# Almost all options means same as for install() cmake command. -# 'MODULE' refers to kernel module itself, SYMVERS refers symvers file. -# -# Unlike to standard install() command, there is no default destination -# directory neither for modules nor for symvers files. -# So, at least one rule should be defined, and 'DESTINATION' option -# should be set for every rule. -# -# TODO: support for 'EXPORT' mode. -function(kbuild_install type) - if(NOT type STREQUAL "TARGETS") - message(FATAL_ERROR "Only 'TARGETS' mode is currently supported") - endif(NOT type STREQUAL "TARGETS") - - parse_install_arguments(kbuild_install - "MODULE;SYMVERS" # Section types - "" "DESTINATION;COMPONENT" "CONFIGURATIONS" # Section keywords classification. - ${ARGN} - ) - - set(kbuild_install_TARGETS ${kbuild_install_GLOBAL_ARGUMENTS}) - if(NOT kbuild_install_TARGETS) - message(FATAL_ERROR "No targets given for kbuild_install() command") - endif(NOT kbuild_install_TARGETS) - - if(NOT kbuild_install_sections) - message(FATAL_ERROR "There is no default destination for install kernel module components, but no section described it is given.") - endif(NOT kbuild_install_sections) - - foreach(section_type ${kbuild_install_sections}) - if(NOT kbuild_install_${section_type}_DESTINATION) - message(FATAL_ERROR "DESTINATION is not defined for section ${section_type}") - endif(NOT kbuild_install_${section_type}_DESTINATION) - # All additional arguments for given section. - set(install_args_${section_type} - DESTINATION "${kbuild_install_${section_type}_DESTINATION}") - if(kbuild_install_${section_type}_CONFIGURATION) - list(APPEND install_args_${section_type} - CONFIGURATION "${kbuild_install_${section_type}_CONFIGURATION}" - ) - endif(kbuild_install_${section_type}_CONFIGURATION) - if(kbuild_install_${section_type}_COMPONENT) - list(APPEND install_args_${section_type} - COMPONENT "${kbuild_install_${section_type}_COMPONENT}" - ) - endif(kbuild_install_${section_type}_COMPONENT) - # Module installation. - if(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL") - # Combine locations for all modules in one list. - set(module_locations) - foreach(t ${kbuild_install_TARGETS}) - kbuild_get_module_location(module_location ${t}) - list(APPEND module_locations ${module_location}) - endforeach(t ${kbuild_install_TARGETS}) - # .. and install them at once. - install(FILES ${module_locations} ${install_args_${section_type}}) - endif(section_type STREQUAL "MODULE" OR section_type STREQUAL "ALL") - # Symvers installation. - if(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL") - # Because of renaming, symvers files should be installed separately. - foreach(t ${kbuild_install_TARGETS}) - kbuild_get_symvers_location(symvers_location ${t}) - get_property(module_name TARGET ${t} PROPERTY KMODULE_MODULE_NAME) - install(FILES ${symvers_location} - RENAME "${module_name}.symvers" - ${install_args_${section_type}} - ) - endforeach(t ${kbuild_install_TARGETS}) - endif(section_type STREQUAL "SYMVERS" OR section_type STREQUAL "ALL") - endforeach(section_type ${kbuild_install_sections}) -endfunction(kbuild_install type) - - -# kbuild_try_compile(RESULT_VAR bindir srcfile|SOURCES src ... -# [CMAKE_FLAGS ] -# [KBUILD_COMPILE_DEFINITIONS flags ...] -# [OUTPUT_VARIABLE var]) -# -# Similar to try_module in simplified form, but compile srcfile as -# kernel module, instead of user space program. -# -# KBUILD_COMPILE_DEFINITIONS contains compiler definition flags for -# build kernel module. -# -# Possible CMAKE_FLAGS which has special semantic: -# KBUILD_INCLUDE_DIRECTORIES - include directories for build kernel module -# KBUILD_LINK_MODULE - symvers file(s) for link module with other modules. -function(kbuild_try_compile RESULT_VAR bindir srcfile) - cmake_parse_arguments(kbuild_try_compile "" "OUTPUT_VARIABLE" "CMAKE_FLAGS;KBUILD_COMPILE_DEFINITIONS" ${ARGN}) - if(srcfile STREQUAL "SOURCES") - set(srcfiles ${kbuild_try_compile_UNPARSED_ARGUMENTS}) - else(srcfile STREQUAL "SOURCES") - set(srcfiles ${srcfile}) - endif(srcfile STREQUAL "SOURCES") - - # Inside try_compile project values of variables - # CMAKE_CURRENT_BINARY_DIR and CMAKE_CURRENT_SOURCE_DIR - # differs from ones in current project. - # - # So make all paths absolute before pass them into try_compile project. - # Note, that copiing files into binary dir is nevertheless performed - # in the try_compile project, because it bases on real current binary dir. - to_abs_path(srcfiles_abs ${srcfiles}) - - # Collect parameters to try_compile() function - set(cmake_flags - "-DSOURCES:STRING=${srcfiles_abs}" # Source file(s) - "-DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}" # Path for search include files. - ${kbuild_try_compile_CMAKE_FLAGS} - ) - - # Parameters for compiler - if(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS) - list(APPEND cmake_flags - "-DKBUILD_COMPILE_DEFINITIONS:STRING=${kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS}" - ) - endif(kbuild_try_compile_KBUILD_COMPILE_DEFINITIONS) - - # Other user-defined cmake flags - if(kbuild_try_compile_CMAKE_FLAGS) - - endif(kbuild_try_compile_CMAKE_FLAGS) - - # Possible definition of output variable. - if(kbuild_try_compile_OUTPUT_VARIABLE) - set(output_variable_def "OUTPUT_VARIABLE" "output_tmp") - else(build_try_compile_OUTPUT_VARIABLE) - set(output_variable_def) - endif(kbuild_try_compile_OUTPUT_VARIABLE) - - - try_compile(result_tmp # Result variable(temporary) - "${bindir}" # Binary directory - "${kbuild_aux_dir}/try_compile_project" # Source directory - "kmodule" # Project name - CMAKE_FLAGS # Flags to CMake: - ${cmake_flags} - ${kbuild_try_compile_flags} - ${output_variable_def} - ) - - if(kbuild_try_compile_OUTPUT_VARIABLE) - # Set output variable for the caller - set("${kbuild_try_compile_OUTPUT_VARIABLE}" "${output_tmp}" PARENT_SCOPE) - endif(kbuild_try_compile_OUTPUT_VARIABLE) - # Set result variable for the caller - set("${RESULT_VAR}" "${result_tmp}" PARENT_SCOPE) -endfunction(kbuild_try_compile RESULT_VAR bindir srcfile) - -########### Auxiliary functions for internal use ####################### -# Per-directory tracking for kbuild compiler flags. -# -# Unlike to standard COMPILE_FLAGS, these flags do not include values -# set for parent directories. -# (There is no generic "fill-with-parent's values" mechanism exists -# in cmake). -# -# So, this property has a little sence for the user. -# It exists only for make effect of kbuild_add_definitions() to -# cross "function" scope. -define_property(DIRECTORY PROPERTY KBUILD_COMPILE_FLAGS - BRIEF_DOCS "Compiler flags used by Kbuild system added in this directory." - FULL_DOCS "Compiler flags used by Kbuild system added in this directory." -) - -# Per-directory tracking for kbuild include directories. -# -# Unlike to standard INCLUDE_DIRECTORIES, these ones do not include values -# set for parent directories. -# (There is no generic "fill-with-parent's values" mechanism exists -# in cmake). -# -# So, this property has a little sence for the user. -# It exists only for make effect of kbuild_include_directories() to -# cross "function" scope. -define_property(DIRECTORY PROPERTY KBUILD_INCLUDE_DIRECTORIES - BRIEF_DOCS "Include directories used by Kbuild system; added in this directory." - FULL_DOCS "Include directories used by Kbuild system; added in this directory." -) - - -# Parameters below are set externally only in try_compile() for subproject, -# which include this file. -# No need to cache them as try_compile() project is not configured by the user. - -# Real top-level source directory. -if(NOT KBUILD_REAL_SOURCE_DIR) - set(KBUILD_REAL_SOURCE_DIR ${CMAKE_SOURCE_DIR}) -endif(NOT KBUILD_REAL_SOURCE_DIR) -# Real top-level binary directory. -if(NOT KBUILD_REAL_BINARY_DIR) - set(KBUILD_REAL_BINARY_DIR ${CMAKE_BINARY_DIR}) -endif(NOT KBUILD_REAL_BINARY_DIR) - -# These flags are passed to the 'make' when compile kernel module. -set(kbuild_additional_make_flags) -# These CMake flags will be passed to try_compile() subproject. -set(kbuild_try_compile_flags - "-DKBUILD_REAL_SOURCE_DIR=${KBUILD_REAL_SOURCE_DIR}" - "-DKBUILD_REAL_BINARY_DIR=${KBUILD_REAL_BINARY_DIR}" -) - -# ARCH and CROSS_COMPILE are passed to submake only when non-empty. -if(ARCH) - list(APPEND kbuild_additional_make_flags "ARCH=${ARCH}") - list(APPEND kbuild_try_compile_flags "-DARCH=${ARCH}") -endif(ARCH) -if(CROSS_COMPILE) - list(APPEND kbuild_additional_make_flags "CROSS_COMPILE=${CROSS_COMPILE}") - list(APPEND kbuild_try_compile_flags "-DCROSS_COMPILE=${CROSS_COMPILE}") -endif(CROSS_COMPILE) - -# List of targets created with kmodule_add_module() without -# 'IMPORTED' option. -# -# This list is traversed in kmodule_finalize_linking() for -# create 'Kbuild' files. -# -# Note, that this list does not contain all defined kernel modules, -# so property normally shouldn't be used by outer code. -define_property(GLOBAL PROPERTY KMODULE_TARGETS - BRIEF_DOCS "List of kernel module targets configured for build" - FULL_DOCS "List of kernel module targets configured for build" -) - -# CMAKE_CURRENT_BINARY_DIR at the moment, when kbuild_add_module() is issued. -define_property(TARGET PROPERTY KMODULE_BINARY_DIR - BRIEF_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built." - FULL_DOCS "CMAKE_CURRENT_BINARY_DIR where module is built." -) - -# List of object files, used for build kernel module. -# -# List may be empty in case of simple build, when target module has same -# name as its only source. -# -# This is internal property for configure 'Kbuild' file. -define_property(TARGET PROPERTY KMODULE_OBJ_SOURCES - BRIEF_DOCS "Object source files for build kernel module." - FULL_DOCS "Object source files for build kernel module." -) - -# Compiler flags, added with kbuild_add_definitions() -# -# Note, that KBUILD_C_FLAGS* are not included here. -# -# This is internal property for configure 'Kbuild' file. -define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS - BRIEF_DOCS "Additional compile flags for build kernel module." - FULL_DOCS "Additional compile flags for build kernel module." -) - -# Include directories, added with kbuild_include_directories(). -# -# This is internal property for configure 'Kbuild' file. -define_property(TARGET PROPERTY KMODULE_COMPILE_FLAGS - BRIEF_DOCS "Additional compile flags for build kernel module." - FULL_DOCS "Additional compile flags for build kernel module." -) - - -# List of symvers files, added by kbuild_link_module(). -# -# This is internal property for configure 'Kbuild' file. -define_property(TARGET PROPERTY KMODULE_DEPEND_SYMVERS - BRIEF_DOCS "Symvers files this module depends on." - FULL_DOCS "Symvers files this module depends on." -) - -# Constants for internal filenames. -set(_kbuild_symvers "Module.symvers") - -# copy_source_to_binary_dir( ) -# -# Helper for the building kernel module. -# -# Make sure that given source file is inside current binary dir. -# That place is writable and has some "uniqeness" garantee for generate -# auxiliary files during build process. -# -# If already inside current binary dir, do nothing and -# set variable to itself. -# -# Otherwise create rule for copy source into "nice" place inside -# current binary dir and set pointed to that place. -function(copy_source_to_binary_dir source new_source_var) - is_path_inside_dir(is_in_current_binary ${CMAKE_CURRENT_BINARY_DIR} "${source}") - if(is_in_current_binary) - # Source is already placed where we want. - set(${new_source_var} "${source}" PARENT_SCOPE) - else(is_in_current_binary) - # Base directory from which count relative source path. - # By default, it is root directory. - set(base_dir "/") - # Try "nicer" base directories. - foreach(d - ${KBUILD_REAL_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${KBUILD_REAL_SOURCE_DIR} - ) - is_path_inside_dir(is_in_d ${d} "${source}") - if(is_in_d) - set(base_dir ${d}) - break() - endif(is_in_d) - endforeach(d) - # Copy source into same relativ dir, but inside current binary one. - file(RELATIVE_PATH source_rel "${base_dir}" "${source}") - set(new_source "${CMAKE_CURRENT_BINARY_DIR}/${source_rel}") - get_filename_component(new_source_dir ${new_source} PATH) - file(MAKE_DIRECTORY "${new_source_dir}") - rule_copy_file("${new_source}" "${source}") - # Return path to the new source. - set(${new_source_var} "${new_source}" PARENT_SCOPE) - endif(is_in_current_binary) -endfunction(copy_source_to_binary_dir source new_source_var) - -# _get_per_build_var(RESULT_VAR variable) -# -# Return value of per-build variable. -macro(_get_per_build_var RESULT_VAR variable) - if(CMAKE_BUILD_TYPE) - string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type_uppercase) - set(${RESULT_VAR} "${${variable}_${_build_type_uppercase}}") - else(CMAKE_BUILD_TYPE) - set(${RESULT_VAR}) - endif(CMAKE_BUILD_TYPE) -endmacro(_get_per_build_var RESULT_VAR variable) - -# _string_join(sep RESULT_VAR str1 str2) -# -# Join strings and using as glue. -# -# Note, that precisely 2 string are joined, not a list of strings. -# This prevents automatic replacing of ';' inside strings while parsing arguments. -macro(_string_join sep RESULT_VAR str1 str2) - if("${str1}" STREQUAL "") - set("${RESULT_VAR}" "${str2}") - elseif("${str2}" STREQUAL "") - set("${RESULT_VAR}" "${str1}") - else("${str1}" STREQUAL "") - set("${RESULT_VAR}" "${str1}${sep}${str2}") - endif("${str1}" STREQUAL "") -endmacro(_string_join sep RESULT_VAR str1 str2) -# _build_get_directory_property_chained(RESULT_VAR []) -# -# Return list of all values for given property in the current directory -# and all parent directories. -# -# If is given, it is used as glue for join values. -# By default, cmake list separator (';') is used. -function(_get_directory_property_chained RESULT_VAR property_name) - set(sep ";") - foreach(arg ${ARGN}) - set(sep "${arg}") - endforeach(arg ${ARGN}) - set(result "") - set(d "${CMAKE_CURRENT_SOURCE_DIR}") - while(NOT "${d}" STREQUAL "") - get_property(p DIRECTORY "${d}" PROPERTY "${property_name}") - # debug - # message("Property ${property_name} for directory ${d}: '${p}'") - _string_join("${sep}" result "${p}" "${result}") - # message("Intermediate result: '${result}'") - get_property(d DIRECTORY "${d}" PROPERTY PARENT_DIRECTORY) - endwhile(NOT "${d}" STREQUAL "") - set("${RESULT_VAR}" "${result}" PARENT_SCOPE) -endfunction(_get_directory_property_chained RESULT_VAR property_name) - -# _kbuild_module_clean_files(module_name -# [C_SOURCE c_source_noext_abs ...] -# [ASM_SOURCE asm_source_noext_abs ...] -# [SHIPPED_SOURCE shipped_source_noext_abs ...]) -# -# Tell CMake that intermediate files, created by kbuild system, -# should be cleaned with 'make clean'. -function(_kbuild_module_clean_files module_name) - cmake_parse_arguments(kbuild_module_clean "" "" "C_SOURCE;ASM_SOURCE;SHIPPED_SOURCE" ${ARGN}) - if(kbuild_module_clean_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unparsed arguments") - endif(kbuild_module_clean_UNPARSED_ARGUMENTS) - - # List common files (names only) for cleaning - set(common_files_names - ".tmp_versions" # Directory - "modules.order" - "Module.markers" - ) - # List module name-depending files (extensions only) for cleaning - set(name_files_ext - ".o" - ".mod.c" - ".mod.o" - ) - # Same but for the files with names starting with a dot ('.'). - set(name_files_dot_ext - ".ko.cmd" - ".mod.o.cmd" - ".o.cmd" - ) - # List source name-depending files (extensions only) for cleaning - set(source_name_files_ext - ".o" - ) - # Same but for the files with names starting with a dot ('.') - set(source_name_files_dot_ext - ".o.cmd" - ".o.d" # This file is created in case of unsuccessfull build - ) - - # Now collect all sort of files into list - set(files_list) - - foreach(name ${common_files_names}) - list(APPEND files_list "${CMAKE_CURRENT_BINARY_DIR}/${name}") - endforeach(name ${common_files_names}) - - foreach(ext ${name_files_ext}) - list(APPEND files_list - "${CMAKE_CURRENT_BINARY_DIR}/${module_name}${ext}") - endforeach(ext ${name_files_ext}) - - foreach(ext ${name_files_dot_ext}) - list(APPEND files_list - "${CMAKE_CURRENT_BINARY_DIR}/.${module_name}${ext}") - endforeach(ext ${name_files_ext}) - - # All the types of sources are processed in a similar way - foreach(obj_source_noext_abs ${kbuild_module_clean_C_SOURCE} - ${kbuild_module_clean_ASM_SOURCE} ${kbuild_module_clean_SHIPPED_SOURCE}) - - get_filename_component(dir ${obj_source_noext_abs} PATH) - get_filename_component(name ${obj_source_noext_abs} NAME) - foreach(ext ${source_name_files_ext}) - list(APPEND files_list "${dir}/${name}${ext}") - endforeach(ext ${source_name_files_ext}) - foreach(ext ${source_name_files_dot_ext}) - list(APPEND files_list "${dir}/.${name}${ext}") - endforeach(ext ${source_name_files_ext}) - endforeach(obj_source_noext_abs) - # Tell CMake that given files should be cleaned. - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${files_list}") -endfunction(_kbuild_module_clean_files module_name) - -# parse_install_arguments(prefix args..) -# -# Helper for parse arguments for install-like command. -# -# All arguments before the first keyword are classified as GLOBAL_ARGUMENTS -# and stored into list ${prefix}_GLOBAL_ARGUMENTS. -# -# describe possible keywords denoting section type. -# At most one section may exist for every type. -# Special type ALL means generic section. -# -# , and describe -# all keywords inside section. -# Values corresponded to these keywords are stored under -# __*. -# Note, that unlike to cmake_parse_arguments(), all arguments inside -# section definition should be either keyword or its value(s). -# Additionally, _ is set to TRUE for every -# encountered section and _sections contains list of such sections. -# -# If non section is currently active, the first section keyword starts -# special generic section. Definitions for this section are stored as -# for section of type ALL. -# If such section exists, it should be the only section. -# -# Function is generic, but currently is used only there. -function(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords) - set(all_keywords ${section_types} ${options} ${one_value_keywords} ${multiple_value_keywords}) - # Type of the currently parsed section('ALL' for ALL section). - set(current_section_type) - # Active section-related keyword for current section. - set(current_section_keyword) - # Classification for @_current_section_keyword: - # 'OPTION', 'ONE' or 'MULTY'. - set(current_section_keyword_type) - - # Clean all previous keyword values. - set("pia_GLOBAL_ARGUMENTS") - foreach(section_type "ALL" ${section_types}) - set(pia_${section_type} "FALSE") - foreach(opt ${options}) - set("pia_${section_type}_${opt}" "FALSE") - endforeach(opt ${options}) - foreach(keyword ${one_value_keywords} ${multiple_value_keywords}) - set("pia_${section_type}_${keyword}") - endforeach(keyword ${one_value_keywords} ${multiple_value_keywords}) - endforeach(section_type "ALL" ${section_types}) - set("pia_sections") - - foreach(arg ${ARGN}) - list(FIND all_keywords ${arg} keyword_index) - if(keyword_index EQUAL "-1") - if(current_section_type) - if(NOT current_section_keyword) - message(FATAL_ERROR "In section ${current_section_type} argument ${arg} does not belong to any keyword.") - endif(NOT current_section_keyword) - if(current_section_keyword_type STREQUAL "ONE") - set("pia_${current_section_type}_${current_section_keyword}" "${arg}") - set(current_section_keyword "") - else(current_section_keyword_type STREQUAL "ONE") - list(APPEND "pia_${current_section_type}_${current_section_keyword}" "${arg}") - endif(current_section_keyword_type STREQUAL "ONE") - else(current_section_type) - list(APPEND "pia_GLOBAL_ARGUMENTS" "${arg}") - endif(current_section_type) - else(keyword_index EQUAL "-1") - if(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE") - message(FATAL_ERROR "Keyword ${arg} found while value for one-value-option ${current_section_keyword} expected.") - endif(current_section_type AND current_section_keyword AND current_section_keyword_type STREQUAL "ONE") - list(FIND section_types "${arg}" section_type_index) - if(section_type_index EQUAL "-1") - if(NOT current_section_type) - set(current_section_type "ALL") - set("pia_${current_section_type}" "TRUE") - list(APPEND "pia_sections" "${current_section_type}") - endif(NOT current_section_type) - list(FIND options ${arg} option_index) - if(option_index EQUAL "-1") - set(current_section_keyword ${arg}) - list(FIND one_value_keywords ${current_section_keyword} one_index) - if(one_index EQUAL "-1") - set(current_section_keyword_type "MULTY") - else(one_index EQUAL "-1") - set(current_section_keyword_type "ONE") - endif(one_index EQUAL "-1") - set("pia_${current_section_type}_${current_section_keyword}") - else(option_index EQUAL "-1") - set("${prefix}_${current_section_type}_${current_section_keyword}" "TRUE") - set(current_section_keyword_type) - endif(option_index EQUAL "-1") - else(section_type_index EQUAL "-1") - if("pia_ALL") - message(FATAL_ERROR "Generic section should be the only section defined") - endif("pia_ALL") - set(current_section_type "${arg}") - if("pia_${current_section_type}") - message(FATAL_ERROR "Section ${current_section_type} is defined twice.") - endif("pia_${current_section_type}") - set("pia_${current_section_type}" "TRUE") - list(APPEND "pia_sections" "${current_section_type}") - # Current keyword is initially undefined for such section. - set(current_section_keyword) - endif(section_type_index EQUAL "-1") - endif(keyword_index EQUAL "-1") - endforeach(arg ${ARGN}) - - # propagate the result variables to the caller - set("${prefix}_GLOBAL_ARGUMENTS" ${pia_GLOBAL_ARGUMENTS} PARENT_SCOPE) - foreach(section_type "ALL" ${section_types}) - set(${prefix}_${section_type} ${pia_${section_type}} PARENT_SCOPE) - foreach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords}) - set("${prefix}_${section_type}_${keyword}" ${pia_${section_type}_${keyword}} PARENT_SCOPE) - endforeach(keyword ${options} ${one_value_keywords} ${multiple_value_keywords}) - endforeach(section_type "ALL" ${section_types}) - set("${prefix}_sections" ${pia_sections} PARENT_SCOPE) -endfunction(parse_install_arguments prefix section_types options one_value_keywords multiple_value_keywords) diff --git a/cmake_targets/tools/MODULES/kmodule.cmake b/cmake_targets/tools/MODULES/kmodule.cmake deleted file mode 100755 index 2912ac115a..0000000000 --- a/cmake_targets/tools/MODULES/kmodule.cmake +++ /dev/null @@ -1,539 +0,0 @@ -set(kmodule_this_module_dir "${CMAKE_SOURCE_DIR}/cmake/modules/") -set(kmodule_test_sources_dir "${CMAKE_SOURCE_DIR}/cmake/kmodule_sources") - -set(kmodule_function_map_file "") -if (CMAKE_CROSSCOMPILING) - if (KEDR_SYSTEM_MAP_FILE) - set (kmodule_function_map_file "${KEDR_SYSTEM_MAP_FILE}") - else (KEDR_SYSTEM_MAP_FILE) -# KEDR_SYSTEM_MAP_FILE is not specified, construct the default path -# to the symbol map file. - set (kmodule_function_map_file - "${KEDR_ROOT_DIR}/boot/System.map-${KBUILD_VERSION_STRING}" - ) - endif (KEDR_SYSTEM_MAP_FILE) -endif (CMAKE_CROSSCOMPILING) - -# List of unreliable functions, that is, the functions that may be -# be exported and mentioned in System.map but still cannot be used -# because no header provides their declarations. -set(unreliable_functions_list - "__kmalloc_node" - "kmem_cache_alloc_node" - "kmem_cache_alloc_node_notrace" - "kmem_cache_alloc_node_trace" -) - -# kmodule_is_function_exist(function_name RESULT_VAR) -# Verify, whether given function exist in the kernel space on the current system. -# RESULT_VAR is TRUE, if function_name exist in the kernel space, FALSE otherwise. -# RESULT_VAR is cached. - -function(kmodule_is_function_exist function_name RESULT_VAR) - check_begin("Looking for ${function_name} in the kernel") - if(NOT DEFINED ${RESULT_VAR}) - check_try() - execute_process( - COMMAND sh "${kmodule_this_module_dir}/kmodule_files/scripts/lookup_kernel_function.sh" - ${function_name} ${kmodule_function_map_file} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE kmodule_is_function_exist_result - OUTPUT_QUIET) - - if (kmodule_is_function_exist_result EQUAL 0) - list(FIND unreliable_functions_list ${function_name} unreliable_function_index) - if(unreliable_function_index GREATER -1) - # Additional verification for unreliable function - kbuild_try_compile(kmodule_function_is_exist_reliable - "${CMAKE_BINARY_DIR}/check_unreliable_functions/${function_name}" - "${kmodule_test_sources_dir}/check_unreliable_functions/${function_name}.c" - ) - if(NOT kmodule_function_is_exist_reliable) - set(kmodule_is_function_exist_result 1) - endif(NOT kmodule_function_is_exist_reliable) - endif(unreliable_function_index GREATER -1) - endif(kmodule_is_function_exist_result EQUAL 0) - - if (kmodule_is_function_exist_result EQUAL 0) - set(${RESULT_VAR} "TRUE" CACHE INTERNAL "Does ${function_name} exist in the kernel?") - elseif(kmodule_is_function_exist_result EQUAL 1) - set(${RESULT_VAR} "FALSE" CACHE INTERNAL "Does ${function_name} exist in the kernel?") - else(kmodule_is_function_exist_result EQUAL 0) - message(FATAL_ERROR -"Cannot determine whether function '${function_name}' exists in the kernel" - ) - endif(kmodule_is_function_exist_result EQUAL 0) - endif(NOT DEFINED ${RESULT_VAR}) - set_bool_string(check_result "found" "not found" ${${RESULT_VAR}}) - check_end(${check_result}) -endfunction(kmodule_is_function_exist function_name RESULT_VAR) - -# Creates the list of functions that actually exist on the -# current system. -# -# kmodule_configure_kernel_functions(output_list -# {[REQUIRED | OPTIONAL] {func | ONE_OF_LIST}} ...) -# -# ONE_OF_LIST := ONE_OF_BEGIN {func ...} ONE_OF_END -# -# There are 2 modes of function lookup: -# OPTIONAL - if the function doesn't exist, it is silently ignored. -# REQUIRED - if the function doesn't exist, FATAL_ERROR message is printed. -# -# Initial mode is REQUIRED, and it can be changed at any time by REQUIRED -# and OPTIONAL keywords. -# -# ONE_OF_BEGIN/ONE_OF_END determine a section for which no more than one -# function among all listed there should exist. FATAL_ERROR message is -# printed otherwise. When mode is REQUIRED, precisely one function must -# exist. -# Inside this section other keywords must not be used (even another -# ONE_OF_BEGIN). - -function(kmodule_configure_kernel_functions output_list) - set(kmodule_configure_kernel_functions_mode "REQUIRED") - set(kmodule_configure_kernel_functions_one_of_section "FALSE") - set(output_list_tmp) - set(${output_list}) - foreach(arg ${ARGN}) - if(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") - if(kmodule_configure_kernel_functions_one_of_section) - message(FATAL_ERROR -"Inside ONE_OF_BEGIN/ONE_OF_END section, other keywords are not allowed." - ) - endif(kmodule_configure_kernel_functions_one_of_section) - set(kmodule_configure_kernel_functions_mode ${arg}) - elseif(arg STREQUAL "ONE_OF_BEGIN") - if(kmodule_configure_kernel_functions_one_of_section) - message(FATAL_ERROR "Nested ONE_OF_BEGIN/ONE_OF_END sections are not allowed.") - endif(kmodule_configure_kernel_functions_one_of_section) - set(kmodule_configure_kernel_functions_one_of_section "TRUE") - set(kmodule_configure_kernel_functions_one_of_section_function) - elseif(arg STREQUAL "ONE_OF_END") - if(NOT kmodule_configure_kernel_functions_one_of_section) - message(FATAL_ERROR "ONE_OF_END without ONE_OF_BEGIN is not allowed.") - endif(NOT kmodule_configure_kernel_functions_one_of_section) - if(kmodule_configure_kernel_functions_one_of_section_function) - list(APPEND output_list_tmp ${kmodule_configure_kernel_functions_one_of_section_function}) - else(kmodule_configure_kernel_functions_one_of_section_function) - if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") - message(FATAL_ERROR -"None of the functions listed in ONE_OF section exist in the kernel but it is required." - ) - endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") - endif(kmodule_configure_kernel_functions_one_of_section_function) - set(kmodule_configure_kernel_functions_one_of_section "FALSE") - else(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") - set(kmodule_func_varname _KMODULE_IS_${arg}_EXIST) - kedr_find_function(${arg} ${kmodule_func_varname}) - if(kmodule_configure_kernel_functions_one_of_section) - if(${kmodule_func_varname}) - if(kmodule_configure_kernel_functions_one_of_section_function) - message(FATAL_ERROR "Two functions from ONE_OF sections exist in the kernel.") - else(kmodule_configure_kernel_functions_one_of_section_function) - set(kmodule_configure_kernel_functions_one_of_section_function ${arg}) - endif(kmodule_configure_kernel_functions_one_of_section_function) - endif(${kmodule_func_varname}) - else(kmodule_configure_kernel_functions_one_of_section) - if(${kmodule_func_varname}) - list(APPEND output_list_tmp ${arg}) - else(${kmodule_func_varname}) - if(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") - message(FATAL_ERROR "Function ${arg} is not found in the kernel but it is required.") - endif(kmodule_configure_kernel_functions_mode STREQUAL "REQUIRED") - endif(${kmodule_func_varname}) - endif(kmodule_configure_kernel_functions_one_of_section) - endif(arg STREQUAL "REQUIRED" OR arg STREQUAL "OPTIONAL") - endforeach(arg ${ARGN}) - if(kmodule_configure_kernel_functions_one_of_section) - message(FATAL_ERROR "Found ONE_OF_BEGIN without ONE_OF_END") - endif(kmodule_configure_kernel_functions_one_of_section) - set(${output_list} ${output_list_tmp} PARENT_SCOPE) -endfunction(kmodule_configure_kernel_functions output_list) - -############################################################################ -# Utility macros to check for particular features. If the particular feature -# is supported, the macros will set the corresponding variable to TRUE, -# otherwise - to FALSE (the name of variable is mentioned in the comments -# for the macro). -############################################################################ - -# Check if the system has everything necessary to build at least simple -# kernel modules. -# The macro sets variable 'MODULE_BUILD_SUPPORTED'. -macro(check_module_build) - check_begin("Checking if kernel modules can be built on this system") - if (NOT MODULE_BUILD_SUPPORTED) - check_try() - kbuild_try_compile(module_build_supported_impl - "${CMAKE_BINARY_DIR}/check_module_build" - "${kmodule_test_sources_dir}/check_module_build/module.c" - ) - set_bool_string(MODULE_BUILD_SUPPORTED "yes" "no" ${module_build_supported_impl} - CACHE INTERNAL "Can kernel modules be built on this system?" - ) - endif (NOT MODULE_BUILD_SUPPORTED) - - check_end("${MODULE_BUILD_SUPPORTED}") - - if (NOT MODULE_BUILD_SUPPORTED) - message(FATAL_ERROR -"There are problems with building kernel modules on this system. " -"Please check that the appropriate kernel headers and build tools " -"are installed." - ) - endif (NOT MODULE_BUILD_SUPPORTED) -endmacro(check_module_build) - -# Check if reliable stack trace information can be obtained. -# This is the case, for example, if the kernel is compiled with support -# for frame pointers and/or stack unwind on. -# The macro sets variable 'STACK_TRACE_RELIABLE'. -macro(check_stack_trace) - check_begin("Checking if stack trace information is reliable") - if (NOT DEFINED STACK_TRACE_RELIABLE) - check_try() - kbuild_try_compile(stack_trace_reliable_impl - "${CMAKE_BINARY_DIR}/check_stack_trace" - "${kmodule_test_sources_dir}/check_stack_trace/module.c" - ) - set_bool_string(STACK_TRACE_RELIABLE "yes" "no" ${stack_trace_reliable_impl} - CACHE INTERNAL "Are stack traces reliable on this system?") - endif (NOT DEFINED STACK_TRACE_RELIABLE) - check_end("${STACK_TRACE_RELIABLE}") - - if (NOT STACK_TRACE_RELIABLE) - message ("\n[WARNING]\n" - "It looks like reliable stack traces cannot be obtained on this system.\n" - "The output of KEDR-based tools like LeakCheck will be less detailed\n" - "(each stack trace shown will contain only one frame).\n" - "If this is not acceptable, you could rebuild the kernel with\n" - "CONFIG_FRAME_POINTER or CONFIG_STACK_UNWIND (if available) set to \"y\"\n" - "and then reconfigure and rebuild KEDR.\n") - endif (NOT STACK_TRACE_RELIABLE) -endmacro(check_stack_trace) - -# Check whether ring buffer is implemented by the kernel. -# Set cache variable RING_BUFFER_IMPLEMENTED according to this checking. -function(check_ring_buffer) - check_begin("Checking if ring buffer is implemented in the kernel") - - if (NOT DEFINED RING_BUFFER_IMPLEMENTED) - check_try() - kbuild_try_compile(ring_buffer_implemented_impl - "${CMAKE_BINARY_DIR}/check_ring_buffer" - "${kmodule_test_sources_dir}/check_ring_buffer/module.c" - ) - - set_bool_string(RING_BUFFER_IMPLEMENTED "yes" "no" "${ring_buffer_implemented_impl}" - CACHE INTERNAL "Whether ring buffer is implemented in the kernel" - ) - endif (NOT DEFINED RING_BUFFER_IMPLEMENTED) - check_end(${RING_BUFFER_IMPLEMENTED}) - - if (NOT RING_BUFFER_IMPLEMENTED) - message("\n[WARNING]\nRing buffer is not supported by the system.\n" - "The tracing facilities as well as call monitoring plugins will not be built.\n" - "If this is not acceptable, you could rebuild the kernel with\n" - "CONFIG_RING_BUFFER set to \"y\" and then reconfigure and rebuild KEDR.\n") - endif (NOT RING_BUFFER_IMPLEMENTED) -endfunction(check_ring_buffer) - -# Check which memory allocator is used by the kernel. -# Set KERNEL_MEMORY_ALLOCATOR to 'slab', 'slub', 'slob' or 'other'. -# -# Some functions in that allocators may have same names, but different signatures. -function(check_allocator) - check_begin("Checking which memory allocator is used by the kernel") - if(NOT DEFINED KERNEL_MEMORY_ALLOCATOR) - check_try() - # Use local variable for detect allocator, - # Cache one will be set at the end - set(allocator "") - if(allocator STREQUAL "") - kbuild_try_compile(is_allocator_slab - "${CMAKE_BINARY_DIR}/check_allocator_slab" - "${kmodule_test_sources_dir}/check_allocator/module.c" - KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLAB" - ) - if (is_allocator_slab) - set(allocator "slab") - endif (is_allocator_slab) - endif(allocator STREQUAL "") - - if(allocator STREQUAL "") - kbuild_try_compile(is_allocator_slub - "${CMAKE_BINARY_DIR}/check_allocator_slub" - "${kmodule_test_sources_dir}/check_allocator/module.c" - KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLUB" - ) - if (is_allocator_slub) - set(allocator "slub") - endif (is_allocator_slub) - endif(allocator STREQUAL "") - - if(allocator STREQUAL "") - kbuild_try_compile(is_allocator_slob - "${CMAKE_BINARY_DIR}/check_allocator_slob" - "${kmodule_test_sources_dir}/check_allocator/module.c" - KBUILD_COMPILE_DEFINITIONS "-DIS_ALLOCATOR_SLOB" - ) - if (is_allocator_slob) - set(allocator "slob") - endif (is_allocator_slub) - endif(allocator STREQUAL "") - - if(allocator STREQUAL "") - set(allocator "other") - endif(allocator STREQUAL "") - - set(KERNEL_MEMORY_ALLOCATOR "${allocator}" CACHE INTERNAL - "Memory allocator which is used by the kernel" - ) - endif (NOT DEFINED KERNEL_MEMORY_ALLOCATOR) - check_end("${KERNEL_MEMORY_ALLOCATOR}") -endfunction(check_allocator) - -# Check if 'kfree_rcu' is available in the kernel (it is likely to be -# a macro or an inline). If it is available, we should handle it as -# 'free' in LeakCheck. As KEDR cannot normally intercept kfree_rcu() -# itself, it needs to intercept call_rcu/call_rcu_sched and check their -# arguments. -# The macro sets variable 'HAVE_KFREE_RCU'. -macro(check_kfree_rcu) - check_begin("Checking if kfree_rcu() is available") - - if (NOT DEFINED HAVE_KFREE_RCU) - check_try() - kbuild_try_compile(have_kfree_rcu_impl - "${CMAKE_BINARY_DIR}/check_kfree_rcu" - "${kmodule_test_sources_dir}/check_kfree_rcu/module.c" - ) - - set_bool_string(HAVE_KFREE_RCU "yes" "no" ${have_kfree_rcu_impl} - CACHE INTERNAL "Is kfree_rcu() available?" - ) - endif () - check_end("${HAVE_KFREE_RCU}") -endmacro(check_kfree_rcu) -############################################################################ - -# Check if posix_acl_from_xattr() accepts struct user_namespace as the -# first argument. -# The macro sets variable 'POSIX_ACL_XATTR_HAS_USER_NS'. -macro(check_xattr_user_ns) - check_begin("Checking if posix_acl_from_xattr() has struct user_namespace * argument") - if (NOT DEFINED POSIX_ACL_XATTR_HAS_USER_NS) - check_try() - kbuild_try_compile(have_xattr_user_ns_impl - "${CMAKE_BINARY_DIR}/check_xattr_user_ns" - "${kmodule_test_sources_dir}/check_xattr_user_ns/module.c" - ) - - set_bool_string(POSIX_ACL_XATTR_HAS_USER_NS "yes" "no" ${have_xattr_user_ns_impl} - CACHE INTERNAL "Does posix_acl_from_xattr() have struct user_namespace argument?" - ) - endif () - check_end("${POSIX_ACL_XATTR_HAS_USER_NS}") -endmacro(check_xattr_user_ns) -############################################################################ - -# Check if hlist_for_each_entry*() macros accept only 'type *pos' argument -# rather than both 'type *tpos' and 'hlist_node *pos' as the loop cursors. -# The macro sets variable 'HLIST_FOR_EACH_ENTRY_POS_ONLY'. -macro(check_hlist_for_each_entry) - check_begin("Checking the signatures of hlist_for_each_entry*() macros") - if (NOT DEFINED HLIST_FOR_EACH_ENTRY_POS_ONLY) - check_try() - kbuild_try_compile(pos_only_impl - "${CMAKE_BINARY_DIR}/check_hlist_for_each_entry" - "${kmodule_test_sources_dir}/check_hlist_for_each_entry/module.c" - ) - set_bool_string(HLIST_FOR_EACH_ENTRY_POS_ONLY "yes" "no" ${pos_only_impl} - CACHE INTERNAL - "Do hlist_for_each_entry*() macros have only 'type *pos' to use as a loop cursor?" - ) - endif () - set_bool_string(check_result "do not use additional loop cursor" "use additional loop cursor" - ${HLIST_FOR_EACH_ENTRY_POS_ONLY}) - check_end(${check_result}) -endmacro(check_hlist_for_each_entry) -############################################################################ - -# Check if 'random32' is available in the kernel. -# The macro sets variable 'KEDR_HAVE_RANDOM32'. -macro(check_random32) - check_begin("Checking if random32() is available") - if (NOT DEFINED KEDR_HAVE_RANDOM32) - check_try() - kbuild_try_compile(have_random32_impl - "${CMAKE_BINARY_DIR}/check_random32" - "${kmodule_test_sources_dir}/check_random32/module.c" - ) - set_bool_string(KEDR_HAVE_RANDOM32 "yes" "no" "${have_random32_impl}" - CACHE INTERNAL "Is random32() available?" - ) - endif () - check_end("${KEDR_HAVE_RANDOM32}") -endmacro(check_random32) -############################################################################ - -# The payload modules should call kedr_find_function() for each kernel -# function they would like to process. If the function is not known -# to KEDR (absent from the "function database", see "functions/" directory), -# kedr_find_function() issues a fatal error. -# -# 'func_name' is the name of the function, -# 'found_var' is the name of the output variable (the variable will evaluate -# as "true" if found, as "false" otherwise). -function (kedr_find_function func_name found_var) - if (NOT DEFINED KEDR_DATA_FILE_${func_name}) - message(FATAL_ERROR "Unsupported function: ${func_name}") - endif (NOT DEFINED KEDR_DATA_FILE_${func_name}) - - # OK, known function. - kmodule_is_function_exist(${func_name} ${found_var}) - if (${found_var}) - # Mark the function as used by at least one payload module. - # This can be used when preparing the tests for call interception. - # The actual value does not matter, it only matters that this - # variable is defined. - set(KEDR_FUNC_USED_${func_name} "yes" CACHE INTERNAL - "Is kernel function ${func_name} used by any payload module?") - set(${found_var} "${${found_var}}" PARENT_SCOPE) - else () - set(${found_var} "NO" PARENT_SCOPE) - endif (${found_var}) -endfunction (kedr_find_function func_name found_var) - -# Returns (in ${path_var}) the path to the .data file for the function -# ${func_name}. The function must be present in the system and -# kedr_find_function() must be called for it before kedr_get_data_for_func(). -function (kedr_get_data_for_func func_name path_var) - if (NOT DEFINED KEDR_FUNC_USED_${func_name}) - message(FATAL_ERROR -"Attempt to lookup data for a function that is not marked as used: " - "${func_name}") - endif (NOT DEFINED KEDR_FUNC_USED_${func_name}) - - set(${path_var} "${KEDR_DATA_FILE_${func_name}}" PARENT_SCOPE) -endfunction (kedr_get_data_for_func func_name path_var) - -# kedr_get_header_data_list(list_var func1 [func2 func3 ...]) -# Get the list of paths to the 'header.data' files for the given functions. -# The functions must be present in the system and # kedr_find_function() -# must be called for each of them before kedr_get_header_data_list() is -# called. -# The resulting list is returned in ${list_var}. It will contain at least -# one item. It will not contain duplicates. -function (kedr_get_header_data_list list_var) - set(hdata_list) - foreach (func ${ARGN}) - if (NOT DEFINED KEDR_FUNC_USED_${func}) - message(FATAL_ERROR -"Attempt to lookup header data for a function that is not marked as used: " - "${func}") - endif (NOT DEFINED KEDR_FUNC_USED_${func}) - list(APPEND hdata_list "${KEDR_HEADER_DATA_FILE_${func}}") - endforeach () - list(REMOVE_DUPLICATES hdata_list) - - list(LENGTH hdata_list hdata_list_len) - if (NOT hdata_list_len) - message(FATAL_ERROR - "kedr_get_header_data_list(): BUG: the output list is empty.") - endif (NOT hdata_list_len) - - set(${list_var} ${hdata_list} PARENT_SCOPE) -endfunction (kedr_get_header_data_list list_var) - -# kedr_create_header_rules( -# header_impl_file header_data_file func1 [func2 ...]) -# Create the rules to generate ${header_impl_file} from -# ${header_data_file} and the specific header files for the given -# functions. -function(kedr_create_header_rules header_impl_file header_data_file - functions) - set(hlist_data) - kedr_get_header_data_list(hlist_data ${functions} ${ARGN}) - to_abs_path(hdata_files_abs ${header_data_file} ${hlist_data}) - add_custom_command(OUTPUT ${header_impl_file} - COMMAND cat ${hdata_files_abs} > ${header_impl_file} - DEPENDS ${hdata_files_abs} - ) -endfunction(kedr_create_header_rules header_impl_file header_data_file - functions) - -# kedr_create_data_rules(func) -# Create the rules to generate ${func}_impl.data from -# ${func}.data (contains processing instructions specific to the current -# payload) and the .data file from "func_db" (contains function signature). -function(kedr_create_data_rules func) - set(func_db_data_file) - kedr_get_data_for_func(${func} func_db_data_file) - - set(func_proc_data_file) - to_abs_path(func_proc_data_file ${func}.data) - - add_custom_command(OUTPUT "${func}_impl.data" - COMMAND printf "\"[group]\\n\"" > "${func}_impl.data" - COMMAND grep -E -v '\\[group\\]' - "${func_db_data_file}" >> "${func}_impl.data" - COMMAND printf "\"\\n\"" >> "${func}_impl.data" - COMMAND grep -E -v '\\[group\\]' - "${func_proc_data_file}" >> "${func}_impl.data" - DEPENDS - "${func_proc_data_file}" - "${func_db_data_file}" - ) -endfunction(kedr_create_data_rules func) - -# kedr_create_payload_module(module_name payload_data_file template_dir) -# Create the rules to build a payload module with the given name. -# 'payload_data_file' defines how the kernel functions are to be processed -# by this payload module. -# 'template_dir' - path to the direcotry containing the templates to be used -# to prepare the source code of the module from 'payload_data_file'. -function(kedr_create_payload_module module_name payload_data_file - template_dir) - - # Rules to build the module - kbuild_add_module(${module_name} - "payload.c" - "functions_support.c" - ) - kbuild_link_module(${module_name} kedr) - - # Rules to obtain the source files of the module - kedr_generate("payload.c" ${payload_data_file} "${template_dir}") - kedr_generate("functions_support.c" ${payload_data_file} "${KEDR_GEN_TEMPLATES_DIR}/functions_support.c") -endfunction(kedr_create_payload_module module_name payload_data_file - template_dir) - -# kedr_create_payload_data(payload_data_file func1 [func2 ...]) -# Create .data files and the header data files for the functions and prepare -# the main .data file (${payload_data_file}) for the payload module. -function(kedr_create_payload_data header_data_file payload_data_file - functions) - set(header_impl_file "header_impl.data") - set(functions_data) - - foreach(func ${functions} ${ARGN}) - list(APPEND functions_data "${func}_impl.data") - kedr_create_data_rules(${func}) - endforeach(func ${functions} ${ARGN}) - - kedr_create_header_rules(${header_impl_file} ${header_data_file} - ${functions} ${ARGN}) - - to_abs_path(payload_data_file_abs ${payload_data_file}) - to_abs_path(source_files_abs ${header_impl_file} ${functions_data}) - - set(payload_data_file_abs "${CMAKE_CURRENT_BINARY_DIR}/${payload_data_file}") - add_custom_command(OUTPUT ${payload_data_file_abs} - COMMAND cat ${source_files_abs} > ${payload_data_file_abs} - DEPENDS ${source_files_abs} - ) -endfunction(kedr_create_payload_data header_data_file payload_data_file - functions) -############################################################################ diff --git a/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt b/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt deleted file mode 100755 index 805d121e6d..0000000000 --- a/cmake_targets/tools/example_oaisim_enb_ue_mme_virtual.txt +++ /dev/null @@ -1,98 +0,0 @@ -#/* -# * 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 example_oaisim_enb_ue_mme_virtual.txt -# brief -# author Lionel Gauthier - -TODO: a document file, PDF for example, with nice pictures, etc -This example shows how to generate and launch enb, 1 ue (NAS still not virtualized in UE) in virtualised mode, mme_gw, hss executables on the same host: - -################ -Configuration -################ -freediameter 1.2.0 (not 1.1.5, 1.1.6,...) has to be installed and patched (done by check_install_oai_software() calling install_freediameter_from_source() in script build_helper) - -Config File: -/etc/hosts must contain the fqdn of the MME and HSS (same since both run on the same host): -(assuming the realm is openair4G.eur) -127.0.0.1 localhost -127.0.1.1 yang.openair4G.eur yang -... - -################ -BUILDING, RUNNING -################ - -Building HSS: -yang@yang:~/openair4G/trunk/cmake_targets$ tools/build_hss -c --connect-to-mme yang.openair4G.eur -t -T --realm openair4G.eur - -Configuring the HSS: -In oai_db (easier for newbies to access HSS database through http://127.0.0.1/phpmyadmin) - In table mmeidentity, enter the record corresponding to your MME: - (idmmeidentity, mmehost, mmerealm) - In table pdn, enter the record allowing an IMSI to connect to an APN - In table users, enter the record corresponding to your USIM card. - -Running the HSS: -yang@yang:~/openair4G/trunk/cmake_targets$ sudo tools/run_hss -g - - - -Building the MME-GW: -yang@yang:~/openair4G/trunk/cmake_targets/tools$ ./build_epc -c -d -t -T --s6a-server - -Configuring the MME-GW: - You can configure in file openair4G/trunk/cmake_targets/tools/epc.local.enb.conf.in the following parameters: - MCC/MNC of your network - SGI interface (outgoing interface of the S/P-GW) - Integrity algorithms, Ciphering algorithms - Please note that DNS addresses are hardcoded in source code (TODO in list). - -Running the MME-GW: -yang@yang:~/openair4G/trunk/cmake_targets/tools$ sudo ./run_epc -l -g -K - - - -Building eNB: -yang@yang:~/openair4G/trunk/cmake_targets$ ./build_oai --oaisim - -Configuring the eNB: - The default configuration file for the eNB is trunk/targets/PROJECTS/GENERIC-LTE-EPC/CONF/enb.band7.generic.oaisim.local_mme.conf - -Running eNB: -yang@yang:~/openair4G/trunk/cmake_targets$ tools/run_enb_ue_virt_s1 -m /tmp -K /tmp/enb_ue_virt_s1_itti.log - - -Putting some IP UL/DL traffic in the bearer: -ping -s 1000 -m 1 192.168.12.100 -I oip1 - - -################ -Tools available: -############### - -1) itti_analyser (list messages exchanged between protocol layers) -2) xforms (Layer 1) -3) vcd (timing mesurements) - - - diff --git a/cmake_targets/tools/make_agent_cache b/cmake_targets/tools/make_agent_cache deleted file mode 100755 index d2eab20fc0..0000000000 --- a/cmake_targets/tools/make_agent_cache +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -CACHE_DIR=/mnt/oai_agent_cache - -if [ ! -d $CACHE_DIR ]; then - echo "Creating cache dir in $CACHE_DIR" - sudo mkdir $CACHE_DIR -fi - -if grep -qs "$CACHE_DIR" /proc/mounts; then - echo "Agent cache is already mounted" -else - echo "Agent cache was not mounted" - echo "Mounting..." - sudo mount -o size=100m -t tmpfs none "$CACHE_DIR" - if [ $? -eq 0 ]; then - echo "Mount success" - else - echo "Something went wrong with the mount" - fi -fi diff --git a/cmake_targets/tools/setup_routes.sh b/cmake_targets/tools/setup_routes.sh deleted file mode 100755 index 67fe250be7..0000000000 --- a/cmake_targets/tools/setup_routes.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -for i in $(seq 1 $1); -do - let table=1000+$i - echo "sudo ip route add 10.0.1.0/24 dev oaitun_ue$i table $table" - sudo ip route add 10.0.1.0/24 dev oaitun_ue$i table $table - echo "sudo ip route add default via 10.0.1.1 dev oaitun_ue$i table $table" - sudo ip route add default via 10.0.1.1 dev oaitun_ue$i table $table - let octet=$i+1 - echo "sudo ip rule add from 10.0.1.$octet table $table" - sudo ip rule add from 10.0.1.$octet table $table -done diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 2772fc5aae..f9740978cd 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -497,8 +497,6 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32 return carrier_freq; } -static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx); - static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) { NR_DL_FRAME_PARMS *fp = &UE->frame_parms; @@ -735,175 +733,6 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) { return rem_samples + next_slot_first_symbol; } -static void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame) -{ - if (!UE->nrUE_config.ntn_config.is_targetcell) - return; - UE->nrUE_config.ntn_config.is_targetcell = false; - - const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn; - const int diff1 = (frame - epoch_frame + 1024) % 1024; - const int diff2 = (epoch_frame - frame + 1024) % 1024; - - int *epoch_hfn = &UE->nrUE_config.ntn_config.epoch_hfn; - if (diff1 < diff2) { // epoch_frame in the past - LOG_I(PHY, "epoch is %d frames in the past\n", diff1); - if (epoch_frame <= frame) - *epoch_hfn = hfn; - else - *epoch_hfn = hfn - 1; - } else { // epoch_frame in the future - LOG_I(PHY, "epoch is %d frames in the future\n", diff2); - if (epoch_frame >= frame) - *epoch_hfn = hfn; - else - *epoch_hfn = hfn + 1; - } - LOG_I(PHY, "setting epoch_hfn = %d\n", *epoch_hfn); -} - -#define SPEED_OF_LIGHT 299792458 - -// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler -static void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx) -{ - const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config; - - // Handle terrestrial networks - if (ntn_config_params->cell_specific_k_offset == 0) { - if (abs_subframe_tx >= 0) - UE->timing_advance_ntn = 0; - UE->dl_Doppler_shift = 0; - UE->ul_Doppler_shift = 0; - return; - } - - const int abs_subframe_epoch = ntn_config_params->epoch_subframe - + ntn_config_params->epoch_sfn * 10 - + ntn_config_params->epoch_hfn * 10240; - const int ms_since_epoch = abs_subframe_tx < 0 ? 0 : abs_subframe_tx - abs_subframe_epoch; - - const position_t pos_sat_0 = ntn_config_params->pos_sat_0; - const position_t vel_sat_0 = ntn_config_params->vel_sat_0; - - position_t pos_sat; - position_t vel_sat; - - const double omega = ntn_config_params->omega; - if (omega) { - const double cos_wt = cos(omega * ms_since_epoch); - const double sin_wt = sin(omega * ms_since_epoch); - - const position_t pos_sat_90 = ntn_config_params->pos_sat_90; - pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt, - pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt, - pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt}; - - const position_t vel_sat_90 = ntn_config_params->vel_sat_90; - vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt, - vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt, - vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt}; - } else { - pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000, - pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000, - pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000}; - vel_sat = vel_sat_0; - } - - position_t pos_ue = {0}; - get_position_coordinates(UE->Mod_id, &pos_ue); - - // calculate directional vector from SAT to UE - const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z}; - - // calculate distance between SAT and UE - const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z); - - // calculate projected velocity from SAT towards UE - const double vel_sat_ue = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance; - - // calculate DL Doppler shift (moving source) - const double dl_Doppler_shift = (vel_sat_ue / (SPEED_OF_LIGHT - vel_sat_ue)) * fp->dl_CarrierFreq; - - // calculate UL Doppler shift (moving target) - const double ul_Doppler_shift = (vel_sat_ue / SPEED_OF_LIGHT) * fp->ul_CarrierFreq; - - // calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000) - const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT; - - const double N_common_ta_adj = ntn_config_params->N_common_ta_adj; - const double N_common_ta_drift = ntn_config_params->N_common_ta_drift; - const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant; - - if (abs_subframe_tx >= 0) { - UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj + N_common_ta_drift * ms_since_epoch / 1e6 - + N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9) - * fp->samples_per_subframe; - } - - UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift; - UE->dl_Doppler_shift = dl_Doppler_shift; - UE->ul_Doppler_shift = ul_Doppler_shift; - - if (abs_subframe_tx < 0) { - LOG_I(PHY, - "satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n", - vel_sat_ue, - dl_Doppler_shift / 1000, - ul_Doppler_shift / 1000); - } -} - -// apply values based on the NTN-Config -static void apply_ntn_config(PHY_VARS_NR_UE *UE, - NR_DL_FRAME_PARMS *fp, - int hfn_rx, - int frame_rx, - int slot_rx, - int *duration_rx_to_tx, - int *timing_advance, - int *ntn_koffset, - bool *ntn_targetcell) -{ - // return if there is no pending update - if (!UE->nrUE_config.ntn_config.params_changed) - return; - - *ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell; - - // skip update if it is for the target cell - if (UE->nrUE_config.ntn_config.is_targetcell) - return; - - UE->nrUE_config.ntn_config.params_changed = false; - - const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config; - - const int mu = fp->numerology_index; - const int koffset = ntn_config_params->cell_specific_k_offset; - - *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); - if (koffset > *ntn_koffset) - *timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu); - else if (koffset < *ntn_koffset) - *timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu); - *ntn_koffset = koffset; - - const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu); - apply_ntn_timing_advance_and_doppler(UE, fp, abs_subframe_tx); - - LOG_I(PHY, - "k_offset: %dms, N_Common_Ta: %fms, drift: %fยตs/s, variant: %fยตs/sยฒ, " - "timing_advance_ntn: %d samples, DL Doppler shift: %fkHz, UL Doppler shift: %fkHz\n", - koffset << mu, - ntn_config_params->N_common_ta_adj, - ntn_config_params->N_common_ta_drift, - ntn_config_params->N_common_ta_drift_variant, - UE->timing_advance_ntn, - UE->dl_Doppler_shift / 1000, - UE->ul_Doppler_shift / 1000); -} - void *UE_thread(void *arg) { //this thread should be over the processing thread to keep in real time diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md index 0e4a630f4b..56e7570de4 100644 --- a/openair1/PHY/CODING/DOC/LDPCImplementation.md +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -40,7 +40,6 @@ Linking C shared module libldpc_aal.so At runtime, to successfully use LDPC accelerators (e.g., Xilinx T2/Intel ACCs), you will need to install the corresponding drivers and tools. Please refer to the dedicated documentation at [LDPC_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_OFFLOAD_SETUP.md). -<<<<<<< HEAD ``` ./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 01:00.0 --nrLDPC_coding_aal.dpdk_core_list 0-1 ``` diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c index 998b95d0d3..86a4b93ddd 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c @@ -12,11 +12,7 @@ data storage. */ #include #include #include -#if defined RHEL_RELEASE_CODE -#include -#else #include -#endif #include #include #include diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c new file mode 100644 index 0000000000..51031d5449 --- /dev/null +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ntn_l1.c @@ -0,0 +1,191 @@ +/* + * 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 + */ + +#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" + +void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame) +{ + if (!UE->nrUE_config.ntn_config.is_targetcell) + return; + UE->nrUE_config.ntn_config.is_targetcell = false; + + const int epoch_frame = UE->nrUE_config.ntn_config.epoch_sfn; + const int diff1 = (frame - epoch_frame + 1024) % 1024; + const int diff2 = (epoch_frame - frame + 1024) % 1024; + + int *epoch_hfn = &UE->nrUE_config.ntn_config.epoch_hfn; + if (diff1 < diff2) { // epoch_frame in the past + LOG_I(PHY, "epoch is %d frames in the past\n", diff1); + if (epoch_frame <= frame) + *epoch_hfn = hfn; + else + *epoch_hfn = hfn - 1; + } else { // epoch_frame in the future + LOG_I(PHY, "epoch is %d frames in the future\n", diff2); + if (epoch_frame >= frame) + *epoch_hfn = hfn; + else + *epoch_hfn = hfn + 1; + } + LOG_I(PHY, "setting epoch_hfn = %d\n", *epoch_hfn); +} + +#define SPEED_OF_LIGHT 299792458 + +// calculate TA and Doppler based on the NTN-Config, if abs_subframe_tx < 0 then apply only Doppler +void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx) +{ + const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config; + + // Handle terrestrial networks + if (ntn_config_params->cell_specific_k_offset == 0) { + if (abs_subframe_tx >= 0) + UE->timing_advance_ntn = 0; + UE->dl_Doppler_shift = 0; + UE->ul_Doppler_shift = 0; + return; + } + + const int abs_subframe_epoch = ntn_config_params->epoch_subframe + + ntn_config_params->epoch_sfn * 10 + + ntn_config_params->epoch_hfn * 10240; + const int ms_since_epoch = abs_subframe_tx < 0 ? 0 : abs_subframe_tx - abs_subframe_epoch; + + const position_t pos_sat_0 = ntn_config_params->pos_sat_0; + const position_t vel_sat_0 = ntn_config_params->vel_sat_0; + + position_t pos_sat; + position_t vel_sat; + + const double omega = ntn_config_params->omega; + if (omega) { + const double cos_wt = cos(omega * ms_since_epoch); + const double sin_wt = sin(omega * ms_since_epoch); + + const position_t pos_sat_90 = ntn_config_params->pos_sat_90; + pos_sat = (position_t){pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt, + pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt, + pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt}; + + const position_t vel_sat_90 = ntn_config_params->vel_sat_90; + vel_sat = (position_t){vel_sat_0.X * cos_wt + vel_sat_90.X * sin_wt, + vel_sat_0.Y * cos_wt + vel_sat_90.Y * sin_wt, + vel_sat_0.Z * cos_wt + vel_sat_90.Z * sin_wt}; + } else { + pos_sat = (position_t){pos_sat_0.X + vel_sat_0.X * ms_since_epoch / 1000, + pos_sat_0.Y + vel_sat_0.Y * ms_since_epoch / 1000, + pos_sat_0.Z + vel_sat_0.Z * ms_since_epoch / 1000}; + vel_sat = vel_sat_0; + } + + position_t pos_ue = {0}; + get_position_coordinates(UE->Mod_id, &pos_ue); + + // calculate directional vector from SAT to UE + const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z}; + + // calculate distance between SAT and UE + const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z); + + // calculate projected velocity from SAT towards UE + const double vel_sat_ue = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance; + + // calculate DL Doppler shift (moving source) + const double dl_Doppler_shift = (vel_sat_ue / (SPEED_OF_LIGHT - vel_sat_ue)) * fp->dl_CarrierFreq; + + // calculate UL Doppler shift (moving target) + const double ul_Doppler_shift = (vel_sat_ue / SPEED_OF_LIGHT) * fp->ul_CarrierFreq; + + // calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000) + const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT; + + const double N_common_ta_adj = ntn_config_params->N_common_ta_adj; + const double N_common_ta_drift = ntn_config_params->N_common_ta_drift; + const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant; + + if (abs_subframe_tx >= 0) { + UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj + N_common_ta_drift * ms_since_epoch / 1e6 + + N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9) + * fp->samples_per_subframe; + } + + UE->freq_offset -= dl_Doppler_shift - UE->dl_Doppler_shift; + UE->dl_Doppler_shift = dl_Doppler_shift; + UE->ul_Doppler_shift = ul_Doppler_shift; + + if (abs_subframe_tx < 0) { + LOG_I(PHY, + "satellite velocity towards UE = %f m/s, DL Doppler shift = %f kHz, UL Doppler shift = %f kHz\n", + vel_sat_ue, + dl_Doppler_shift / 1000, + ul_Doppler_shift / 1000); + } +} + +// apply values based on the NTN-Config +void apply_ntn_config(PHY_VARS_NR_UE *UE, + NR_DL_FRAME_PARMS *fp, + int hfn_rx, + int frame_rx, + int slot_rx, + int *duration_rx_to_tx, + int *timing_advance, + int *ntn_koffset, + bool *ntn_targetcell) +{ + // return if there is no pending update + if (!UE->nrUE_config.ntn_config.params_changed) + return; + + *ntn_targetcell = UE->nrUE_config.ntn_config.is_targetcell; + + // skip update if it is for the target cell + if (UE->nrUE_config.ntn_config.is_targetcell) + return; + + UE->nrUE_config.ntn_config.params_changed = false; + + const fapi_nr_ntn_config_t *ntn_config_params = &UE->nrUE_config.ntn_config; + + const int mu = fp->numerology_index; + const int koffset = ntn_config_params->cell_specific_k_offset; + + *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); + if (koffset > *ntn_koffset) + *timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu); + else if (koffset < *ntn_koffset) + *timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu); + *ntn_koffset = koffset; + + const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu); + apply_ntn_timing_advance_and_doppler(UE, fp, abs_subframe_tx); + + LOG_I(PHY, + "k_offset: %dms, N_Common_Ta: %fms, drift: %fยตs/s, variant: %fยตs/sยฒ, " + "timing_advance_ntn: %d samples, DL Doppler shift: %fkHz, UL Doppler shift: %fkHz\n", + koffset << mu, + ntn_config_params->N_common_ta_adj, + ntn_config_params->N_common_ta_drift, + ntn_config_params->N_common_ta_drift_variant, + UE->timing_advance_ntn, + UE->dl_Doppler_shift / 1000, + UE->ul_Doppler_shift / 1000); +} 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 ed348986e8..2a24902295 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -330,7 +330,17 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, pdsch_scope_req_t *scope_req); int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData); - +void apply_ntn_config(PHY_VARS_NR_UE *UE, + NR_DL_FRAME_PARMS *fp, + int hfn_rx, + int frame_rx, + int slot_rx, + int *duration_rx_to_tx, + int *timing_advance, + int *ntn_koffset, + bool *ntn_targetcell); +void fix_ntn_epoch_hfn(PHY_VARS_NR_UE *UE, int hfn, int frame); +void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx); void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid); void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb); diff --git a/openair1/PHY/TOOLS/calibration_test.c b/openair1/PHY/TOOLS/calibration_test.c index 4d88ab542a..8007040499 100644 --- a/openair1/PHY/TOOLS/calibration_test.c +++ b/openair1/PHY/TOOLS/calibration_test.c @@ -108,10 +108,6 @@ int main(int argc, char **argv) { .sdr_addrs=usrp_addrs, //! Auto calibration flag .autocal={0}, - //! rf devices work with x bits iqs when oai have its own iq format - //! the two following parameters are used to convert iqs - .iq_txshift=0, - .iq_rxrescale=0, //! Configuration file for LMS7002M .configFilename="", //! remote IP/MAC addr for Ethernet interface diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index f2452221d6..18f6f3f605 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1742,7 +1742,7 @@ int main(int argc, char *argv[]) printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time"); printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time"); printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time"); - printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time"); + printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate matching time"); printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time"); printStatIndent(&gNB->rx_srs_stats,"RX SRS time"); printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time"); diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index ed93cdaadf..3bfd2e20a2 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -473,8 +473,8 @@ typedef struct { cell_id_t id; // Cell type uint8_t type; - // Time UE Stayed in Cell - long time_in_cell; + // Time UE Stayed in Cell (seconds) + uint16_t time_in_cell; // Cause ngap_cause_t *cause; } last_visited_ngran_cell_info_t; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index af6bf37aff..477e39a60a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -38,7 +38,7 @@ #include "executables/softmodem-common.h" #include -void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y) +static void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15, const uint32_t Y) { LOG_T(NR_MAC_DCI, "Filling search candidates for DCI\n"); @@ -89,7 +89,7 @@ void fill_dci_search_candidates(const NR_SearchSpace_t *ss, fapi_nr_dl_config_dc rel15->number_of_candidates = i; } -NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id) +static NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int coreset_id) { if (config->commonControlResourceSet && coreset_id == config->commonControlResourceSet->controlResourceSetId) return config->commonControlResourceSet; @@ -362,12 +362,12 @@ bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per return monitor; } -bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac, - const NR_SearchSpace_t *ss, - const int abs_slot, - const int frame, - const int slot, - const int slots_per_frame) +static bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac, + const NR_SearchSpace_t *ss, + const int abs_slot, + const int frame, + const int slot, + const int slots_per_frame) { const int duration = ss->duration ? *ss->duration : 1; int period, offset; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 860089165f..a409cbe653 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -58,13 +58,6 @@ static const int nb_symbols_excluding_dmrs[11][2][2] /* 14 */ {{ 12 , 12 } , { 10 , 10 }}, }; -static int get_deltatf(uint16_t nb_of_prbs, - uint8_t N_symb_PUCCH, - uint8_t freq_hop_flag, - uint8_t add_dmrs_flag, - int N_sc_ctrl_RB, - int O_UCI); - // โˆ†MPR according to Table 6.2.2-3 38.101-1 static float get_delta_mpr(uint16_t nr_band, frame_type_t frame_type, int scs, int channel_bandwidth, int n_prbs, int start_prb, int power_class) { @@ -256,6 +249,28 @@ int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame) return delta_tpc_sum; } +static int get_deltatf(uint16_t nb_of_prbs, + uint8_t N_symb_PUCCH, + uint8_t freq_hop_flag, + uint8_t add_dmrs_flag, + int N_sc_ctrl_RB, + int O_UCI) +{ + int DELTA_TF; + int O_CRC = compute_pucch_crc_size(O_UCI); + int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag]; + float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb; + float K1 = 6; + if (O_UCI + O_CRC < 12) + DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE))); + else { + float K2 = 2.4; + float BPRE = (O_UCI + O_CRC) / N_RE; + DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1)); + } + return DELTA_TF; +} + // PUCCH Power control according to 38.213 section 7.2.1 int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, int scs, @@ -399,28 +414,6 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, return pucch_power; } -static int get_deltatf(uint16_t nb_of_prbs, - uint8_t N_symb_PUCCH, - uint8_t freq_hop_flag, - uint8_t add_dmrs_flag, - int N_sc_ctrl_RB, - int O_UCI) -{ - int DELTA_TF; - int O_CRC = compute_pucch_crc_size(O_UCI); - int N_symb = N_symb_PUCCH < 4 ? N_symb_PUCCH : nb_symbols_excluding_dmrs[N_symb_PUCCH - 4][add_dmrs_flag][freq_hop_flag]; - float N_RE = nb_of_prbs * N_sc_ctrl_RB * N_symb; - float K1 = 6; - if (O_UCI + O_CRC < 12) - DELTA_TF = 10 * log10((double)(((K1 * (O_UCI)) / N_RE))); - else { - float K2 = 2.4; - float BPRE = (O_UCI + O_CRC) / N_RE; - DELTA_TF = 10 * log10((double)(pow(2, (K2 * BPRE)) - 1)); - } - return DELTA_TF; -} - // Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission // computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16 // Assumptions: diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 241a56b180..3ba221386f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -104,58 +104,7 @@ static const int sequence_cyclic_shift_2_harq_ack_bits[4] /* HARQ-ACK Value (0,0) (0,1) (1,0) (1,1) */ /* Sequence cyclic shift */ = { 0, 3, 9, 6 }; -/* \brief Function called by PHY to process the received RAR and check that the preamble matches what was sent by the gNB. It -provides the timing advance and t-CRNTI. -@param Mod_id Index of UE instance -@param CC_id Index to a component carrier -@param frame Frame index -@param ra_rnti RA_RNTI value -@param dlsch_buffer Pointer to dlsch_buffer containing RAR PDU -@param t_crnti Pointer to PHY variable containing the T_CRNTI -@param preamble_index Preamble Index used by PHY to transmit the PRACH. This should match the received RAR to trigger the rest of -random-access procedure -@param selected_rar_buffer the output buffer for storing the selected RAR header and RAR payload -@returns timing advance or 0xffff if preamble doesn't match -*/ -static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id); - -/*! \fn int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); - \brief This function schedules a positive or negative SR for schedulingRequestID sr_id - depending on the presence of any active SR and the prohibit timer. - If the max number of retransmissions is reached, it triggers a new RA */ -static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); - -static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig); - -static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig, - CSI_mapping_t mapping_type); -static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - const NR_CSI_MeasConfig_t *csi_MeasConfig); - -static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp); - -static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id); - -static void set_harq_status(NR_UE_MAC_INST_t *mac, - uint8_t pucch_id, - uint8_t harq_id, - int8_t delta_pucch, - uint16_t data_toul_fb, - uint8_t dai, - int n_CCE, - int N_CCE, - frame_t frame, - int slot); - -int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload) +static int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload) { int mcs = 0; if (O_SR == 0 || sr_payload == 0) { /* only ack is transmitted TS 36.213 9.2.3 UE procedure for reporting HARQ-ACK */ @@ -197,14 +146,6 @@ const initial_pucch_resource_t initial_pucch_resource[16] = { /* 15 */ { 1, 0, 14, 0, 4, { 0, 3, 6, 9 } }, }; -static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, - const nfapi_nr_dci_formats_e dci_format, - const uint8_t dci_size, - const uint16_t rnti, - const int ss_type, - const uint8_t *dci_pdu, - const int slot); - int get_rnti_type(const NR_UE_MAC_INST_t *mac, const uint16_t rnti) { const RA_config_t *ra = &mac->ra; @@ -523,6 +464,71 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p return 0; } +static void set_harq_status(NR_UE_MAC_INST_t *mac, + uint8_t pucch_id, + uint8_t harq_id, + int8_t delta_pucch, + uint16_t data_toul_fb, + uint8_t dai, + int n_CCE, + int N_CCE, + frame_t frame, + int slot) +{ + NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_id]; + current_harq->active = true; + current_harq->ack_received = false; + current_harq->pucch_resource_indicator = pucch_id; + current_harq->n_CCE = n_CCE; + current_harq->N_CCE = N_CCE; + current_harq->dai_cumul = 0; + current_harq->delta_pucch = delta_pucch; + // FIXME k0 != 0 currently not taken into consideration + int slots_per_frame = mac->frame_structure.numb_slots_frame; + current_harq->ul_frame = frame; + current_harq->ul_slot = slot + data_toul_fb; + if (current_harq->ul_slot >= slots_per_frame) { + current_harq->ul_frame = (frame + current_harq->ul_slot / slots_per_frame) % MAX_FRAME_NUMBER; + current_harq->ul_slot %= slots_per_frame; + } + // counter DAI in DCI ranges from 0 to 3 + // we might have more than 4 HARQ processes to report per PUCCH + // we need to keep track of how many DAI we received in a slot (dai_cumul) despite the modulo operation + int highest_dai = -1; + int temp_dai = dai; + const int num_dl_harq = get_nrofHARQ_ProcessesForPDSCH(&mac->sc_info); + for (int i = 0; i < num_dl_harq; i++) { + // looking for other active HARQ processes with feedback in the same frame/slot + if (i == harq_id) + continue; + NR_UE_DL_HARQ_STATUS_t *harq = &mac->dl_harq_info[i]; + if (harq->active && + harq->ul_frame == current_harq->ul_frame && + harq->ul_slot == current_harq->ul_slot) { + // highest_dai is the largest cumulative dai in the set of HARQ allocations for a given slot + if (harq->dai_cumul > highest_dai) + highest_dai = harq->dai_cumul - 1; + } + } + + current_harq->dai_cumul = temp_dai + 1; // DAI = 0 (temp_dai) corresponds to 1st assignment and so on + // if temp_dai is less or equal than cumulative highest dai for given slot + // it's an indication dai was reset due to modulo 4 operation + if (temp_dai <= highest_dai) { + int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4) + current_harq->dai_cumul += (mod4_count * 4); + } + LOG_D(NR_MAC, + "Setting harq_status for harq_id %d, dl %d.%d, sched ul %d.%d fb time %d total dai %d\n", + harq_id, + frame, + slot, + current_harq->ul_frame, + current_harq->ul_slot, + data_toul_fb, + current_harq->dai_cumul); +} + static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, @@ -1486,27 +1492,6 @@ static int8_t nr_ue_process_dci(NR_UE_MAC_INST_t *mac, return -1; } -nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci) -{ - LOG_D(NR_MAC, - "Received dci indication (rnti %x, dci format %d, n_CCE %d, payloadSize %d, payload %llx)\n", - dci->rnti, - dci->dci_format, - dci->n_CCE, - dci->payloadSize, - *(unsigned long long *)dci->payloadBits); - const nr_dci_format_t format = - nr_extract_dci_info(mac, dci->dci_format, dci->payloadSize, dci->rnti, dci->ss_type, dci->payloadBits, slot); - if (format == NR_DCI_NONE) - return NR_DCI_NONE; - int ret = nr_ue_process_dci(mac, frame, slot, mac->def_dci_pdu_rel15[slot] + format, dci, format); - if (ret < 0) { - mac->stats.bad_dci++; - return NR_DCI_NONE; - } - return format; -} - void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) { LOG_D(NR_MAC, "(%d.%d) Received measurements from L1\n", frame, slot); @@ -1530,71 +1515,6 @@ void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slo l1_measurements->rsrp_dBm); } -static void set_harq_status(NR_UE_MAC_INST_t *mac, - uint8_t pucch_id, - uint8_t harq_id, - int8_t delta_pucch, - uint16_t data_toul_fb, - uint8_t dai, - int n_CCE, - int N_CCE, - frame_t frame, - int slot) -{ - NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_id]; - current_harq->active = true; - current_harq->ack_received = false; - current_harq->pucch_resource_indicator = pucch_id; - current_harq->n_CCE = n_CCE; - current_harq->N_CCE = N_CCE; - current_harq->dai_cumul = 0; - current_harq->delta_pucch = delta_pucch; - // FIXME k0 != 0 currently not taken into consideration - int slots_per_frame = mac->frame_structure.numb_slots_frame; - current_harq->ul_frame = frame; - current_harq->ul_slot = slot + data_toul_fb; - if (current_harq->ul_slot >= slots_per_frame) { - current_harq->ul_frame = (frame + current_harq->ul_slot / slots_per_frame) % MAX_FRAME_NUMBER; - current_harq->ul_slot %= slots_per_frame; - } - // counter DAI in DCI ranges from 0 to 3 - // we might have more than 4 HARQ processes to report per PUCCH - // we need to keep track of how many DAI we received in a slot (dai_cumul) despite the modulo operation - int highest_dai = -1; - int temp_dai = dai; - const int num_dl_harq = get_nrofHARQ_ProcessesForPDSCH(&mac->sc_info); - for (int i = 0; i < num_dl_harq; i++) { - // looking for other active HARQ processes with feedback in the same frame/slot - if (i == harq_id) - continue; - NR_UE_DL_HARQ_STATUS_t *harq = &mac->dl_harq_info[i]; - if (harq->active && - harq->ul_frame == current_harq->ul_frame && - harq->ul_slot == current_harq->ul_slot) { - // highest_dai is the largest cumulative dai in the set of HARQ allocations for a given slot - if (harq->dai_cumul > highest_dai) - highest_dai = harq->dai_cumul - 1; - } - } - - current_harq->dai_cumul = temp_dai + 1; // DAI = 0 (temp_dai) corresponds to 1st assignment and so on - // if temp_dai is less or equal than cumulative highest dai for given slot - // it's an indication dai was reset due to modulo 4 operation - if (temp_dai <= highest_dai) { - int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4) - current_harq->dai_cumul += (mod4_count * 4); - } - LOG_D(NR_MAC, - "Setting harq_status for harq_id %d, dl %d.%d, sched ul %d.%d fb time %d total dai %d\n", - harq_id, - frame, - slot, - current_harq->ul_frame, - current_harq->ul_slot, - data_toul_fb, - current_harq->dai_cumul); -} - initial_pucch_resource_t get_initial_pucch_resource(const int idx) { return initial_pucch_resource[idx]; @@ -2566,51 +2486,11 @@ bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sche return (number_harq_feedback > 0); } -bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, frame_t frame, int slot) -{ - NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; - - if(!pucch_Config || - !pucch_Config->schedulingRequestResourceToAddModList || - pucch_Config->schedulingRequestResourceToAddModList->list.count == 0) - return false; // SR not configured - - int sr_count = 0; - for (int id = 0; id < pucch_Config->schedulingRequestResourceToAddModList->list.count; id++) { - NR_SchedulingRequestResourceConfig_t *sr_Config = pucch_Config->schedulingRequestResourceToAddModList->list.array[id]; - int SR_period; int SR_offset; - - find_period_offset_SR(sr_Config, &SR_period, &SR_offset); - const int n_slots_frame = mac->frame_structure.numb_slots_frame; - int sfn_sf = frame * n_slots_frame + slot; - - if ((sfn_sf - SR_offset) % SR_period == 0) { - LOG_D(MAC, "Scheduling Request active in frame %d slot %d \n", frame, slot); - if (!sr_Config->resource) { - LOG_E(MAC, "No resource associated with SR. SR not scheduled\n"); - break; - } - NR_PUCCH_Resource_t *sr_pucch = - find_pucch_resource_from_list(pucch_Config->resourceToAddModList, *sr_Config->resource); - AssertFatal(sr_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n"); - pucch->pucch_resource = sr_pucch; - pucch->n_sr = 1; - /* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */ - int ret = nr_ue_get_SR(mac, frame, slot, sr_Config->schedulingRequestID); - if (ret < 0) { - memset(pucch, 0, sizeof(*pucch)); - return false; - } - pucch->sr_payload = ret; - sr_count++; - AssertFatal(sr_count < 2, "Cannot handle more than 1 SR per slot yet\n"); - } - } - return sr_count > 0; -} - -static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id) +/*! \fn int nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); + \brief This function schedules a positive or negative SR for schedulingRequestID sr_id + depending on the presence of any active SR and the prohibit timer. + If the max number of retransmissions is reached, it triggers a new RA */ +static int nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id) { // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info; @@ -2660,6 +2540,50 @@ static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR return -1; } +bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, frame_t frame, int slot) +{ + NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; + + if(!pucch_Config || + !pucch_Config->schedulingRequestResourceToAddModList || + pucch_Config->schedulingRequestResourceToAddModList->list.count == 0) + return false; // SR not configured + + int sr_count = 0; + for (int id = 0; id < pucch_Config->schedulingRequestResourceToAddModList->list.count; id++) { + NR_SchedulingRequestResourceConfig_t *sr_Config = pucch_Config->schedulingRequestResourceToAddModList->list.array[id]; + int SR_period; int SR_offset; + + find_period_offset_SR(sr_Config, &SR_period, &SR_offset); + const int n_slots_frame = mac->frame_structure.numb_slots_frame; + int sfn_sf = frame * n_slots_frame + slot; + + if ((sfn_sf - SR_offset) % SR_period == 0) { + LOG_D(MAC, "Scheduling Request active in frame %d slot %d \n", frame, slot); + if (!sr_Config->resource) { + LOG_E(MAC, "No resource associated with SR. SR not scheduled\n"); + break; + } + NR_PUCCH_Resource_t *sr_pucch = + find_pucch_resource_from_list(pucch_Config->resourceToAddModList, *sr_Config->resource); + AssertFatal(sr_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n"); + pucch->pucch_resource = sr_pucch; + pucch->n_sr = 1; + /* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */ + int ret = nr_ue_get_SR(mac, frame, slot, sr_Config->schedulingRequestID); + if (ret < 0) { + memset(pucch, 0, sizeof(*pucch)); + return false; + } + pucch->sr_payload = ret; + sr_count++; + AssertFatal(sr_count < 2, "Cannot handle more than 1 SR per slot yet\n"); + } + } + return sr_count > 0; +} + // section 5.2.5 of 38.214 int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep) { @@ -2855,52 +2779,6 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, return csi; } -csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, - int csi_report_id, - CSI_mapping_t mapping_type, - NR_CSI_MeasConfig_t *csi_MeasConfig) -{ - AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n"); - csi_payload_t csi = {0}; - struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; - NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; - if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) { - switch (csi_reportconfig->ext2->reportQuantity_r16->present) { - case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: - csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: - LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n"); - break; - default: - AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present); - } - } else { - switch (csi_reportconfig->reportQuantity.present) { - case NR_CSI_ReportConfig__reportQuantity_PR_none: - break; - case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); - break; - default: - AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present); - } - } - return csi; -} - // Comparison function for sorting SSB RSRP measurements in descending order static int compare_ssb_rsrp(const void *a, const void *b) { @@ -2909,6 +2787,16 @@ static int compare_ssb_rsrp(const void *a, const void *b) return mb->ssb_rsrp_dBm - ma->ssb_rsrp_dBm; } +// returns index from differential RSRP +// according to Table 10.1.6.1-2 in 38.133 +static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp) +{ + int diff = best_rsrp-current_rsrp; + if (diff>30) + return 15; + else + return (diff>>1); +} static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, struct NR_CSI_ReportConfig *csi_reportconfig, @@ -3121,49 +3009,300 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, return csi; } -// returns index from differential RSRP -// according to Table 10.1.6.1-2 in 38.133 -static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp) +csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, + int csi_report_id, + CSI_mapping_t mapping_type, + NR_CSI_MeasConfig_t *csi_MeasConfig) { - int diff = best_rsrp-current_rsrp; - if (diff>30) - return 15; - else - return (diff>>1); + AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n"); + csi_payload_t csi = {0}; + struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; + NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; + if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) { + switch (csi_reportconfig->ext2->reportQuantity_r16->present) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n"); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present); + } + } else { + switch (csi_reportconfig->reportQuantity.present) { + case NR_CSI_ReportConfig__reportQuantity_PR_none: + break; + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present); + } + } + return csi; } -void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) +static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, int frame, int slot) { - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; + ul_time_alignment->ta_command = ta; + ul_time_alignment->ta_apply = type; + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs); + const int n_slots_frame = mac->frame_structure.numb_slots_frame; + ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; + ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame; + // start or restart the timeAlignmentTimer associated with the indicated TAG + nr_timer_start(&mac->time_alignment_timer); +} - LOG_D(NR_MAC, - "In [%d.%d] Handling DLSCH PDU type %d\n", - dl_info->frame, - dl_info->slot, - dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type); +static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot) +{ + RAR_grant_t rar_grant; + RA_config_t *ra = &mac->ra; +#ifdef DEBUG_RAR + // CSI + unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01); +#endif - // Processing MAC PDU - // it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs - switch (dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type) { - case FAPI_NR_RX_PDU_TYPE_DLSCH : - // start or restart dataInactivityTimer if any MAC entity receives a MAC SDU for DTCH logical channel, - // DCCH logical channel, or CCCH logical channel - if (mac->data_inactivity_timer) - nr_timer_start(mac->data_inactivity_timer); - // DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" - if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { - trigger_MAC_UE_RA(mac, NULL); + // TPC + unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07); + ra->Msg3_TPC = (tpc_command << 1) - 6; + + // MCS + rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4); + // time alloc + rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f); + // frequency alloc + rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12)); + // frequency hopping + rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2); + + // Schedule Msg3 + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; + const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id]; + const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); + NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP, + *ra_SS->controlResourceSetId, + ra_SS->searchSpaceType->present, + TYPE_RA_RNTI_, + rar_grant.Msg3_t_alloc); + if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) { + LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); + // resume RAR response window timer if MSG2 decoding failed + nr_timer_suspension(&mac->ra.response_window_timer); + return; + } + frame_t frame_tx = 0; + int slot_tx = 0; + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs); + int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); + + // TA command + // if the timeAlignmentTimer associated with this TAG is not running + if (!nr_timer_is_active(&mac->time_alignment_timer)) { + const int ta = rar->TA2 + (rar->TA1 << 5); + set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx); + LOG_W(MAC, "received TA command %d\n", 31 + ta); + } + // else ignore the received Timing Advance Command + +#ifdef DEBUG_RAR + LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); + LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); + LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); + + LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); + LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); + + LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); + LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); + + LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); + LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); + LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); + + LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); + LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); + + LOG_I(NR_MAC, + "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n", + frame, + slot, + mac->ue_id, + rar_grant.Msg3_t_alloc, + rar_grant.Msg3_f_alloc, + ta_command, + rar_grant.mcs, + rar_grant.freq_hopping, + tpc_command); +#endif + + if (ret != -1) { + uint16_t rnti = mac->crnti; + // Upon successful reception, set the T-CRNTI to the RAR value + // if the RA preamble is selected among the contention-based RA Preambles + if (!ra->cfra) { + ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8); + rnti = ra->t_crnti; + if (!mac->msg3_C_RNTI) + nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false); + } + fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH); + if (!pdu) + return; + // Config Msg3 PDU + int ret = nr_config_pusch_pdu(mac, + &tda_info, + &pdu->pusch_config_pdu, + NULL, + NULL, + &rar_grant, + rnti, + NR_SearchSpace__searchSpaceType_PR_common, + NR_DCI_NONE); + if (ret != 0) + remove_ul_config_last_item(pdu); + release_ul_config(pdu, false); + } +} + +///////////////////////////////////// +// Random Access Response PDU // +// TS 38.213 ch 8.2 // +// TS 38.321 ch 6.2.3 // +///////////////////////////////////// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise +//| E | T | R A P I D |// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// +//| R | T A |// +//| T A | UL grant |// +//| UL grant |// +//| UL grant |// +//| UL grant |// +//| T C - R N T I |// +//| T C - R N T I |// +///////////////////////////////////// +// UL grant (27 bits) // +///////////////////////////////////// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise +//|-------------------|FHF|F_alloc|// +//| Freq allocation |// +//| F_alloc |Time allocation|// +//| MCS | TPC |CSI|// +///////////////////////////////////// +// TbD WIP Msg3 development ongoing +// - apply UL grant freq alloc & time alloc as per 8.2 TS 38.213 +// - apply tpc command +// WIP fix: +// - time domain indication hardcoded to 0 for k2 offset +// - extend TS 38.213 ch 8.3 Msg3 PUSCH +// - b buffer +// - ulsch power offset +// - optimize: mu_pusch, j and table_6_1_2_1_1_2_time_dom_res_alloc_A are already defined in nr_ue_procedures +static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) +{ + frame_t frame = dl_info->frame; + int slot = dl_info->slot; + + if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack == 0) { + LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] CRC check failed on RAR (NAK)\n", mac->ue_id, frame, slot); + return; + } + + RA_config_t *ra = &mac->ra; + ra->t_crnti = 0; + uint8_t n_subPDUs = 0; // number of RAR payloads + uint8_t n_subheaders = 0; // number of MAC RAR subheaders + uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu; + NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer + NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer + uint8_t preamble_index = ra->ra_PreambleIndex; + uint16_t rnti = mac->ra.ra_rnti; + + T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot), + T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length)); + + ra->RA_backoff_limit = 0; + LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index); + + while (1) { + n_subheaders++; + if (rarh->T == 1) { + n_subPDUs++; + LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti); + } else { + int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi; + int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; + ra->RA_backoff_limit = bi_ms * slots_per_ms; + LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms); + if (((NR_RA_HEADER_BI *)rarh)->E == 1) { + rarh += sizeof(NR_RA_HEADER_BI); + continue; + } else { break; } - nr_ue_process_mac_pdu(mac, dl_info, pdu_id); + } + if (rarh->RAPID == preamble_index) { + // The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after + // successful reception of a Random Access Response containing Random Access Preamble identifiers + // that matches the transmitted PREAMBLE_INDEX. + nr_timer_stop(&ra->response_window_timer); + LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID); + rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR)); + handle_rar_reception(mac, rar, frame, slot); + if (ra->cfra) + nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot); break; - case FAPI_NR_RX_PDU_TYPE_RAR : - nr_ue_process_rar(mac, dl_info, pdu_id); + } + if (rarh->E == 0) { + LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] Received RAR preamble (%d) doesn't match the intended RAPID (%d)\n", + mac->ue_id, + frame, + slot, + rarh->RAPID, + preamble_index); + // resume RAR response window timer if MSG2 decoding failed + nr_timer_suspension(&mac->ra.response_window_timer); break; - default : - AssertFatal(false, "Invalid DLSCH PDU type\n"); + } else { + rarh += sizeof(NR_MAC_RAR) + 1; + } } - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); + +#ifdef DEBUG_RAR + LOG_D(NR_MAC, + "[DEBUG_RAR] (%d,%d) number of RAR subheader %d; number of RAR pyloads %d\n", + frame, + slot, + n_subheaders, + n_subPDUs); + LOG_D(NR_MAC, + "[DEBUG_RAR] Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n", + *(uint8_t *) rarh, + rar[0], + rar[1], + rar[2], + rar[3], + rar[4], + rar[5], + rarh->RAPID, + preamble_index); +#endif + return; } // #define EXTRACT_DCI_ITEM(val,size) val= readBits(dci_pdu, &pos, size); @@ -3615,17 +3754,25 @@ static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, return format; } -static void set_time_alignment(NR_UE_MAC_INST_t *mac, int ta, ta_type_t type, int frame, int slot) +nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci) { - NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; - ul_time_alignment->ta_command = ta; - ul_time_alignment->ta_apply = type; - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs); - const int n_slots_frame = mac->frame_structure.numb_slots_frame; - ul_time_alignment->frame = (frame + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; - ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame; - // start or restart the timeAlignmentTimer associated with the indicated TAG - nr_timer_start(&mac->time_alignment_timer); + LOG_D(NR_MAC, + "Received dci indication (rnti %x, dci format %d, n_CCE %d, payloadSize %d, payload %llx)\n", + dci->rnti, + dci->dci_format, + dci->n_CCE, + dci->payloadSize, + *(unsigned long long *)dci->payloadBits); + const nr_dci_format_t format = + nr_extract_dci_info(mac, dci->dci_format, dci->payloadSize, dci->rnti, dci->ss_type, dci->payloadBits, slot); + if (format == NR_DCI_NONE) + return NR_DCI_NONE; + int ret = nr_ue_process_dci(mac, frame, slot, mac->def_dci_pdu_rel15[slot] + format, dci, format); + if (ret < 0) { + mac->stats.bad_dci++; + return NR_DCI_NONE; + } + return format; } static bool check_ra_contention_resolution(const uint8_t *pdu, const uint8_t *cont_res) @@ -4055,240 +4202,36 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, return mac_ce - pdu; } -static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot) +void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) { - RAR_grant_t rar_grant; - RA_config_t *ra = &mac->ra; -#ifdef DEBUG_RAR - // CSI - unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01); -#endif + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_IN); - // TPC - unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07); - ra->Msg3_TPC = (tpc_command << 1) - 6; + LOG_D(NR_MAC, + "In [%d.%d] Handling DLSCH PDU type %d\n", + dl_info->frame, + dl_info->slot, + dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type); - // MCS - rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4); - // time alloc - rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f); - // frequency alloc - rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12)); - // frequency hopping - rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2); - - // Schedule Msg3 - const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; - const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id]; - const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); - NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP, - *ra_SS->controlResourceSetId, - ra_SS->searchSpaceType->present, - TYPE_RA_RNTI_, - rar_grant.Msg3_t_alloc); - if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) { - LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); - // resume RAR response window timer if MSG2 decoding failed - nr_timer_suspension(&mac->ra.response_window_timer); - return; - } - frame_t frame_tx = 0; - int slot_tx = 0; - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->phy_config.config_req.ntn_config, mac->current_UL_BWP->scs); - int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); - - // TA command - // if the timeAlignmentTimer associated with this TAG is not running - if (!nr_timer_is_active(&mac->time_alignment_timer)) { - const int ta = rar->TA2 + (rar->TA1 << 5); - set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx); - LOG_W(MAC, "received TA command %d\n", 31 + ta); - } - // else ignore the received Timing Advance Command - -#ifdef DEBUG_RAR - LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); - LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); - LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); - - LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); - LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); - - LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); - LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); - - LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); - LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); - LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); - - LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); - LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); - - LOG_I(NR_MAC, - "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n", - frame, - slot, - mac->ue_id, - rar_grant.Msg3_t_alloc, - rar_grant.Msg3_f_alloc, - ta_command, - rar_grant.mcs, - rar_grant.freq_hopping, - tpc_command); -#endif - - if (ret != -1) { - uint16_t rnti = mac->crnti; - // Upon successful reception, set the T-CRNTI to the RAR value - // if the RA preamble is selected among the contention-based RA Preambles - if (!ra->cfra) { - ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8); - rnti = ra->t_crnti; - if (!mac->msg3_C_RNTI) - nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false); - } - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH); - if (!pdu) - return; - // Config Msg3 PDU - int ret = nr_config_pusch_pdu(mac, - &tda_info, - &pdu->pusch_config_pdu, - NULL, - NULL, - &rar_grant, - rnti, - NR_SearchSpace__searchSpaceType_PR_common, - NR_DCI_NONE); - if (ret != 0) - remove_ul_config_last_item(pdu); - release_ul_config(pdu, false); - } -} - -///////////////////////////////////// -// Random Access Response PDU // -// TS 38.213 ch 8.2 // -// TS 38.321 ch 6.2.3 // -///////////////////////////////////// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise -//| E | T | R A P I D |// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// -//| R | T A |// -//| T A | UL grant |// -//| UL grant |// -//| UL grant |// -//| UL grant |// -//| T C - R N T I |// -//| T C - R N T I |// -///////////////////////////////////// -// UL grant (27 bits) // -///////////////////////////////////// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise -//|-------------------|FHF|F_alloc|// -//| Freq allocation |// -//| F_alloc |Time allocation|// -//| MCS | TPC |CSI|// -///////////////////////////////////// -// TbD WIP Msg3 development ongoing -// - apply UL grant freq alloc & time alloc as per 8.2 TS 38.213 -// - apply tpc command -// WIP fix: -// - time domain indication hardcoded to 0 for k2 offset -// - extend TS 38.213 ch 8.3 Msg3 PUSCH -// - b buffer -// - ulsch power offset -// - optimize: mu_pusch, j and table_6_1_2_1_1_2_time_dom_res_alloc_A are already defined in nr_ue_procedures -static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) -{ - frame_t frame = dl_info->frame; - int slot = dl_info->slot; - - if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack == 0) { - LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] CRC check failed on RAR (NAK)\n", mac->ue_id, frame, slot); - return; - } - - RA_config_t *ra = &mac->ra; - ra->t_crnti = 0; - uint8_t n_subPDUs = 0; // number of RAR payloads - uint8_t n_subheaders = 0; // number of MAC RAR subheaders - uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu; - NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer - NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer - uint8_t preamble_index = ra->ra_PreambleIndex; - uint16_t rnti = mac->ra.ra_rnti; - - T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot), - T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length)); - - ra->RA_backoff_limit = 0; - LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index); - - while (1) { - n_subheaders++; - if (rarh->T == 1) { - n_subPDUs++; - LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti); - } else { - int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi; - int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; - ra->RA_backoff_limit = bi_ms * slots_per_ms; - LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms); - if (((NR_RA_HEADER_BI *)rarh)->E == 1) { - rarh += sizeof(NR_RA_HEADER_BI); - continue; - } else { + // Processing MAC PDU + // it parses MAC CEs subheaders, MAC CEs, SDU subheaderds and SDUs + switch (dl_info->rx_ind->rx_indication_body[pdu_id].pdu_type) { + case FAPI_NR_RX_PDU_TYPE_DLSCH : + // start or restart dataInactivityTimer if any MAC entity receives a MAC SDU for DTCH logical channel, + // DCCH logical channel, or CCCH logical channel + if (mac->data_inactivity_timer) + nr_timer_start(mac->data_inactivity_timer); + // DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" + if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { + trigger_MAC_UE_RA(mac, NULL); break; } - } - if (rarh->RAPID == preamble_index) { - // The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after - // successful reception of a Random Access Response containing Random Access Preamble identifiers - // that matches the transmitted PREAMBLE_INDEX. - nr_timer_stop(&ra->response_window_timer); - LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID); - rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR)); - handle_rar_reception(mac, rar, frame, slot); - if (ra->cfra) - nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot); + nr_ue_process_mac_pdu(mac, dl_info, pdu_id); break; - } - if (rarh->E == 0) { - LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] Received RAR preamble (%d) doesn't match the intended RAPID (%d)\n", - mac->ue_id, - frame, - slot, - rarh->RAPID, - preamble_index); - // resume RAR response window timer if MSG2 decoding failed - nr_timer_suspension(&mac->ra.response_window_timer); + case FAPI_NR_RX_PDU_TYPE_RAR : + nr_ue_process_rar(mac, dl_info, pdu_id); break; - } else { - rarh += sizeof(NR_MAC_RAR) + 1; - } + default : + AssertFatal(false, "Invalid DLSCH PDU type\n"); } - -#ifdef DEBUG_RAR - LOG_D(NR_MAC, - "[DEBUG_RAR] (%d,%d) number of RAR subheader %d; number of RAR pyloads %d\n", - frame, - slot, - n_subheaders, - n_subPDUs); - LOG_D(NR_MAC, - "[DEBUG_RAR] Received RAR (%02x|%02x.%02x.%02x.%02x.%02x.%02x) for preamble %d/%d\n", - *(uint8_t *) rarh, - rar[0], - rar[1], - rar[2], - rar[3], - rar[4], - rar[5], - rarh->RAPID, - preamble_index); -#endif - return; + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SEND_SDU, VCD_FUNCTION_OUT); } - diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index c21a0ce3bd..2818c20c37 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -57,30 +57,6 @@ AssertFatal(ret == 0, "Failure in mutex management ret=%d\n", a); \ } -static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP); -static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac); - -static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, - NR_SINGLE_ENTRY_PHR_MAC_CE *phr, - float P_CMAX, - float tx_power, - frame_t frame, - slot_t slot); -static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, - int cc_id, - frame_t frame, - slot_t slot, - uint8_t gNB_index, - uint8_t *ulsch_buffer, - const uint32_t buflen, - int tx_power, - int P_MAX, - bool *BSRsent); - -static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP); -static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot); -static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot); - static void clear_ul_config_request(NR_UE_MAC_INST_t *mac) { int slots = mac->frame_structure.numb_slots_frame; @@ -1131,6 +1107,205 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, return srs_scheduled; } +static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) +{ + NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; + fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu; + ta->ta_frame = ul_time_alignment->frame; + ta->ta_slot = ul_time_alignment->slot; + ta->is_rar = ul_time_alignment->ta_apply == rar_ta; + ta->ta_command = ul_time_alignment->ta_command; + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND; + dl_config->number_pdus += 1; + ul_time_alignment->ta_apply = no_ta; +} + +static NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measconfig, + NR_BWP_Id_t dl_bwp_id, + NR_NZP_CSI_RS_ResourceId_t csi_id) +{ + bool found = false; + for (int csi_list = 0; csi_list < csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { + NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list]; + if(csires->bwp_Id != dl_bwp_id) + continue; + struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList *resset = &csires->csi_RS_ResourceSetList; + if(resset->present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) + continue; + if(!resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) + continue; + for(int i = 0; i < resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count; i++) { + NR_NZP_CSI_RS_ResourceSetId_t *res_id = resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[i]; + AssertFatal(res_id, "NR_NZP_CSI_RS_ResourceSetId shouldn't be NULL\n"); + struct NR_CSI_MeasConfig__nzp_CSI_RS_ResourceSetToAddModList *res_list = csi_measconfig->nzp_CSI_RS_ResourceSetToAddModList; + AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n"); + for (int j = 0; j < res_list->list.count; j++) { + NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j]; + if (*res_id != csi_res->nzp_CSI_ResourceSetId) + continue; + for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) { + AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n"); + if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) { + found = true; + break; + } + } + if (found && csi_res->trs_Info) + // CRI-RS for Tracking (not implemented yet) + // in this case we there is no associated CSI report + // therefore to signal this we return a value higher than + // maxNrofCSI-ResourceConfigurations + return NR_maxNrofCSI_ResourceConfigurations + 1; + else if (found) + return csires->csi_ResourceConfigId; + } + } + } + return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID +} + +static uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id) +{ + uint8_t meas_bitmap = 0; + if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations) + return meas_bitmap; // CSI-RS for tracking + for(int i = 0; i < csi_measconfig->csi_ReportConfigToAddModList->list.count; i++) { + NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i]; + if(report_config->resourcesForChannelMeasurement != csi_res_id) + continue; + // bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1 + switch (report_config->reportQuantity.present) { + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: + meas_bitmap += (1 << 1) + (1 << 5); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: + meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + meas_bitmap += (1 << 1) + (1 << 4); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + meas_bitmap += 1; + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4); + break; + default: + AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present); + } + } + return meas_bitmap; +} + +static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) +{ + if (!mac->sc_info.csi_MeasConfig) + return; + + NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; + + if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL) + return; + + fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot); + NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; + NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id; + + int mu = current_DL_BWP->scs; + uint16_t bwp_size = current_DL_BWP->BWPSize; + uint16_t bwp_start = current_DL_BWP->BWPStart; + + for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++) { + NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; + int period, offset; + csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset); + if((frame * mac->frame_structure.numb_slots_frame + slot-offset) % period != 0) + continue; + NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId); + // do not schedule reseption of this CSI-RS if not associated with current BWP + if(csi_res_id < 0) + continue; + LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot); + fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csirs_config_pdu.csirs_config_rel15; + csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id); + csirs_config_pdu->subcarrier_spacing = mu; + csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0; + + if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations) + csirs_config_pdu->csi_type = 0; // TRS + else + csirs_config_pdu->csi_type = 1; // NZP-CSI-RS + + csirs_config_pdu->scramb_id = nzpcsi->scramblingID; + csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8; + if (nzpcsi->powerControlOffsetSS) + csirs_config_pdu->power_control_offset_ss = *nzpcsi->powerControlOffsetSS; + else + csirs_config_pdu->power_control_offset_ss = 1; // 0 dB + + configure_csi_resource_mapping(csirs_config_pdu, &nzpcsi->resourceMapping, bwp_size, bwp_start); + + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS; + dl_config->number_pdus += 1; + } +} + +static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot) +{ + if (!mac->sc_info.csi_MeasConfig) + return; + + NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; + + if (csi_measconfig->csi_IM_ResourceToAddModList == NULL) + return; + + fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot); + NR_CSI_IM_Resource_t *imcsi; + int period, offset; + + NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; + int mu = current_DL_BWP->scs; + uint16_t bwp_size = current_DL_BWP->BWPSize; + uint16_t bwp_start = current_DL_BWP->BWPStart; + + for (int id = 0; id < csi_measconfig->csi_IM_ResourceToAddModList->list.count; id++){ + imcsi = csi_measconfig->csi_IM_ResourceToAddModList->list.array[id]; + csi_period_offset(NULL,imcsi->periodicityAndOffset,&period,&offset); + if((frame * mac->frame_structure.numb_slots_frame + slot - offset ) %period != 0) + continue; + fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csiim_config_pdu.csiim_config_rel15; + csiim_config_pdu->bwp_size = bwp_size; + csiim_config_pdu->bwp_start = bwp_start; + csiim_config_pdu->subcarrier_spacing = mu; + csiim_config_pdu->start_rb = imcsi->freqBand->startingRB; + csiim_config_pdu->nr_of_rbs = imcsi->freqBand->nrofRBs; + // As specified in 5.2.2.4 of 38.214 + switch (imcsi->csi_IM_ResourceElementPattern->present) { + case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0: + for (int i = 0; i < 4; i++) { + csiim_config_pdu->k_csiim[i] = + (imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1); + csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2); + } + break; + case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1: + for (int i = 0; i < 4; i++) { + csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i; + csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1; + } + break; + default: + AssertFatal(1 == 0, "Invalid CSI-IM pattern\n"); + } + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM; + dl_config->number_pdus += 1; + } +} + // Performs : // 1. TODO: Call RRC for link status return to PHY // 2. TODO: Perform SR/BSR procedures for scheduling feedback @@ -1341,260 +1516,179 @@ static void nr_update_bsr(NR_UE_MAC_INST_t *mac, uint32_t *LCG_bytes) } } -void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) +static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods) { - int cc_id = ul_info->cc_id; - frame_t frame_tx = ul_info->frame; - slot_t slot_tx = ul_info->slot; - uint32_t gNB_index = ul_info->gNB_index; + int config_period = prach_occasion_info->frame_info[0]; + int frame_period = config_period * association_periods; + int frame_in_period = frame % frame_period; + if (association_periods > 1) { + int current_assoc_period = frame_in_period / config_period; + if (current_assoc_period != prach_occasion_info->association_period_idx) + return false; + frame_in_period %= config_period; + } + if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211) + return true; + else + return false; +} +// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x +// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3. +// - todo: +// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config +static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP) +{ RA_config_t *ra = &mac->ra; - if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) { - init_RA(mac, frame_tx); - // perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a) - ra_resource_selection(mac); - } + // Get any valid PRACH occasion in the current slot for the selected SSB index + prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info; - if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE) - nr_ue_prach_scheduler(mac, frame_tx, slot_tx); - - bool BSRsent = false; - if (mac->state == UE_CONNECTED) { - nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx); - nr_update_rlc_buffers_status(mac, frame_tx, slot_tx, gNB_index); - } - - // Schedule ULSCH only if the current frame and slot match those in ul_config_req - // AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus) - uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES]; - int number_of_pdus = 0; - - fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx); - if (!ulcfg_pdu) + if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods)) return; - LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx); - while (ulcfg_pdu->pdu_type != FAPI_NR_END) { - uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus]; - if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) { - nfapi_nr_ue_pusch_pdu_t *pdu = &ulcfg_pdu->pusch_config_pdu; - uint32_t TBS_bytes = pdu->pusch_data.tb_size; - LOG_D(NR_MAC, - "harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n", - pdu->pusch_data.harq_process_id, - pdu->pusch_data.new_data_indicator, - TBS_bytes, - ra->ra_state); - pdu->tx_request_body.fapiTxPdu = NULL; - if ((ra->ra_state == nrRA_WAIT_RAR || ra->ra_state == nrRA_WAIT_MSGB) && !ra->cfra) { - nr_get_Msg3_MsgA_PUSCH_payload(mac, ulsch_input_buffer, TBS_bytes); - for (int k = 0; k < TBS_bytes; k++) { - LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]); + if (is_ul_slot(slotP, &mac->frame_structure)) { + if (slotP == prach_occasion_info->slot) { + fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH); + if (!pdu) { + LOG_E(NR_MAC, "Error in PRACH allocation\n"); + return; + } + + int format = prach_occasion_info->format; + fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config; + pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){ + .phys_cell_id = mac->physCellId, + .num_prach_ocas = 1, + .prach_slot = prach_occasion_info->slot, + .prach_start_symbol = prach_occasion_info->start_symbol, + .num_ra = prach_occasion_info->fdm, + .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config), + .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index, + .restricted_set = prach_config->restricted_set_config, + .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1}; + + LOG_I(NR_MAC, + "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", + frameP, + pdu->prach_config_pdu.prach_slot, + pdu->prach_config_pdu.prach_start_symbol, + pdu->prach_config_pdu.num_ra); + + switch (format) { // single PRACH format + case 0: + pdu->prach_config_pdu.prach_format = 0; + break; + case 1: + pdu->prach_config_pdu.prach_format = 1; + break; + case 2: + pdu->prach_config_pdu.prach_format = 2; + break; + case 3: + pdu->prach_config_pdu.prach_format = 3; + break; + case 0xa1: + pdu->prach_config_pdu.prach_format = 4; + break; + case 0xa2: + pdu->prach_config_pdu.prach_format = 5; + break; + case 0xa3: + pdu->prach_config_pdu.prach_format = 6; + break; + case 0xb1: + pdu->prach_config_pdu.prach_format = 7; + break; + case 0xb4: + pdu->prach_config_pdu.prach_format = 8; + break; + case 0xc0: + pdu->prach_config_pdu.prach_format = 9; + break; + case 0xc2: + pdu->prach_config_pdu.prach_format = 10; + break; + default: + AssertFatal(false, "Invalid PRACH format"); + } + + pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex; + pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); + release_ul_config(pdu, false); + nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, + .mac = mac, + .module_id = mac->ue_id, + .CC_id = 0 /*TBR fix*/}; + if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) + mac->if_module->scheduled_response(&scheduled_response); + + T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot), + T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power)); + + const int n_slots_frame = mac->frame_structure.numb_slots_frame; + if (ra->ra_type == RA_4_STEP) { + ra->ra_state = nrRA_WAIT_RAR; + // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH + // the response window timer should be started at that time + // but for processing reasons it is better to start it here and to add the slot difference + // that also takes into account the rx to tx slot offset + int next_slot = (slotP + 1) % n_slots_frame; + int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER; + int add_slots = 1; + NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id]; + const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); + while (!is_dl_slot(next_slot, &mac->frame_structure) + || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, ra_SS)) { + int temp_slot = (next_slot + 1) % n_slots_frame; + next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER; + next_slot = temp_slot; + add_slots++; } - pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer; - pdu->tx_request_body.pdu_length = TBS_bytes; - number_of_pdus++; - T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx), - T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes)); + add_slots += GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mac->current_DL_BWP->scs); + nr_timer_setup(&ra->response_window_timer, ra->response_window_setup_time + add_slots, 1); + nr_timer_start(&ra->response_window_timer); + } else if (ra->ra_type == RA_2_STEP) { + NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource = + mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16; + slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame; + frame_t msgA_pusch_frame = + (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024; + + fapi_nr_ul_config_request_pdu_t *pdu = + lockGet_ul_config(mac, msgA_pusch_frame, msgA_pusch_slot, FAPI_NR_UL_CONFIG_TYPE_PUSCH); + if (!pdu) + return; + + // Config Msg3/MsgA-PUSCH PDU + NR_tda_info_t tda_info = {0}; + AssertFatal(msgA_PUSCH_Resource->startSymbolAndLengthMsgA_PO_r16, + "Only SLIV based on startSymbolAndLengthMsgA_PO_r16 implemented\n"); + + int ret = nr_config_pusch_pdu(mac, + &tda_info, + &pdu->pusch_config_pdu, + NULL, + NULL, + NULL, + mac->ra.ra_rnti, + NR_SearchSpace__searchSpaceType_PR_common, + NR_DCI_NONE); + + if (ret != 0) + remove_ul_config_last_item(pdu); + release_ul_config(pdu, false); + + LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]); + ra->ra_state = nrRA_WAIT_MSGB; + ra->t_crnti = 0; + mac->crnti = 0; + ra->ra_rnti = 0; } else { - if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator - && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) { - if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { - // UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" - trigger_MAC_UE_RA(mac, NULL); - return; - } - // Getting IP traffic to be transmitted - int tx_power = pdu->tx_power; - int P_CMAX = nr_get_Pcmax(mac->p_Max, - mac->nr_band, - mac->frame_structure.frame_type, - mac->frequency_range, - mac->current_UL_BWP->channel_bandwidth, - pdu->qam_mod_order, - false, - mac->current_UL_BWP->scs, - mac->current_UL_BWP->BWPSize, - pdu->transform_precoding, - pdu->rb_size, - pdu->rb_start); - - nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes, tx_power, P_CMAX, &BSRsent); - pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer; - pdu->tx_request_body.pdu_length = TBS_bytes; - number_of_pdus++; - T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx), - T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes)); - // start or restart dataInactivityTimer if any MAC entity transmits a MAC SDU for DTCH logical channel, - // or DCCH logical channel - if (mac->data_inactivity_timer) - nr_timer_start(mac->data_inactivity_timer); - } + AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type); } - - if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) { - LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx); - // 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3 - // transmission - nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index); - } - if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) { - LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx); - nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index); - } - if (ra->ra_state == nrRA_WAIT_MSGB && !ra->cfra) { - LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-MsgA-PUSCH transmitted\n", frame_tx, slot_tx); - } - } - ulcfg_pdu++; - } - release_ul_config(ulcfg_pdu, false); - - if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING) - nr_ue_pucch_scheduler(mac, frame_tx, slot_tx); - - if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) { - LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); - nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx, - .mac = mac, - .module_id = mac->ue_id, - .CC_id = cc_id, - .phy_data = ul_info->phy_data}; - mac->if_module->scheduled_response(&scheduled_response); - } - - if(mac->state == UE_CONNECTED) - nr_update_sr(mac, BSRsent); - // Global variables implicit logic - // far away, BSR_reporting_active is set - mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE; - - // update Bj for all active lcids before LCP procedure - if (mac->current_UL_BWP) { - LOG_D(NR_MAC, "%4d.%2d Logical Channel Prioritization\n", frame_tx, slot_tx); - for (int i = 0; i < mac->lc_ordered_list.count; i++) { - nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; - int lcid = lc_info->lcid; - // max amount of data that can be buffered/accumulated in a logical channel buffer - uint32_t bucketSize_max = lc_info->bucket_size; - // measure Bj increment the value of Bj by product PBR * T - NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); - int32_t bj = sched_info->Bj; - if (lc_info->pbr < UINT_MAX) { - uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented - // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s - uint32_t pbr_ms = lc_info->pbr / 1000; - bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms - } - else - bj = INT_MAX; - // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization - sched_info->Bj = min(bj, bucketSize_max); - // reset bj timer - nr_timer_start(&sched_info->Bj_timer); - } - } -} - -static uint8_t nr_locate_BsrIndexByBufferSize(int size, int value) -{ - if (value == 0) { - return 0; //elseif (value > 150000) return 63; - } - - uint32_t (*get_bsr_value)(int); - if (size == NR_SHORT_BSR_TABLE_SIZE) - get_bsr_value = &get_short_bsr_value; - else - get_bsr_value = &get_long_bsr_value; - - int jl = 0; // lower bound - int ju = size - 1; // upper bound - // determine the order of the the table: 1 if ascending order of table, 0 otherwise - bool ascend = (*get_bsr_value)(ju) >= (*get_bsr_value)(jl) ? 1 : 0; - while (ju - jl > 1) { //If we are not yet done, - int jm = (ju + jl) / 2; // compute a midpoint, - if ((value >= (*get_bsr_value)(jm)) == ascend) { - jl = jm; // replace the lower limit - } else { - ju = jm; //replace the upper limit - } - - LOG_T(NR_MAC, - "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", - jm, - (*get_bsr_value)(jm), - value); - } - - if (value == (*get_bsr_value)(jl)) { - return jl; - } else { - return jl + 1; //equally ju - } -} - -// PUSCH scheduler: -// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, -// - where K2 is the offset between the slot in which UL DCI is received and the slot -// - in which ULSCH should be scheduled. K2 is configured in RRC configuration. -// PUSCH Msg3 scheduler: -// - scheduled by RAR UL grant according to 8.3 of TS 38.213 -// Note: Msg3 tx in the uplink symbols of mixed slot -int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, - const uint8_t is_Msg3, - const frame_t current_frame, - const int current_slot, - frame_t *frame_tx, - int *slot_tx, - const long k2) -{ - int delta = 0; - const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - - // Get the numerology to calculate the Tx frame and slot - int mu = current_UL_BWP->scs; - int slots_per_frame = mac->frame_structure.numb_slots_frame; - - // k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1 - // PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon - - if (is_Msg3) { - - delta = get_delta_for_k2(mu); - - AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to " - "%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", - k2, - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu)); - - *slot_tx = (current_slot + k2 + delta) % slots_per_frame; - *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; - } else { - AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " - "gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", - k2, - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), - GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu)); - - if (k2 < 0) { // This can happen when a false DCI is received - LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); - return -1; - } - - // Calculate TX slot and frame - *slot_tx = (current_slot + k2) % slots_per_frame; - *frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER; - } - - LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta); - return 0; + } // is_nr_prach_slot + } // if is_nr_UL_slot } static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, @@ -1782,472 +1876,43 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot } } -static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot) +static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, + NR_SINGLE_ENTRY_PHR_MAC_CE *phr, + float P_CMAX, + float tx_power, + frame_t frame, + slot_t slot) { - if (!mac->sc_info.csi_MeasConfig) - return; - - NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; - - if (csi_measconfig->csi_IM_ResourceToAddModList == NULL) - return; - - fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot); - NR_CSI_IM_Resource_t *imcsi; - int period, offset; - - NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; - int mu = current_DL_BWP->scs; - uint16_t bwp_size = current_DL_BWP->BWPSize; - uint16_t bwp_start = current_DL_BWP->BWPStart; - - for (int id = 0; id < csi_measconfig->csi_IM_ResourceToAddModList->list.count; id++){ - imcsi = csi_measconfig->csi_IM_ResourceToAddModList->list.array[id]; - csi_period_offset(NULL,imcsi->periodicityAndOffset,&period,&offset); - if((frame * mac->frame_structure.numb_slots_frame + slot - offset ) %period != 0) - continue; - fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csiim_config_pdu.csiim_config_rel15; - csiim_config_pdu->bwp_size = bwp_size; - csiim_config_pdu->bwp_start = bwp_start; - csiim_config_pdu->subcarrier_spacing = mu; - csiim_config_pdu->start_rb = imcsi->freqBand->startingRB; - csiim_config_pdu->nr_of_rbs = imcsi->freqBand->nrofRBs; - // As specified in 5.2.2.4 of 38.214 - switch (imcsi->csi_IM_ResourceElementPattern->present) { - case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0: - for (int i = 0; i < 4; i++) { - csiim_config_pdu->k_csiim[i] = - (imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1); - csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2); - } - break; - case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1: - for (int i = 0; i < 4; i++) { - csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i; - csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1; - } - break; - default: - AssertFatal(1 == 0, "Invalid CSI-IM pattern\n"); - } - dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM; - dl_config->number_pdus += 1; + nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info; + // Value mapping according to 38.133 10.1.18.1 + const int PC_MAX_00 = -29; + *phr = (NR_SINGLE_ENTRY_PHR_MAC_CE){.PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f}; + // Value mapping according to 38.133 10.1.17.1.1 + const int POWER_HEADROOM_55 = 22; + int headroom = P_CMAX - tx_power; + if (headroom < POWER_HEADROOM_55) { + const int POWER_HEADROOM_0 = -32; + phr->PH = max(0, headroom - POWER_HEADROOM_0); + } else { + phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2); } -} -NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measconfig, - NR_BWP_Id_t dl_bwp_id, - NR_NZP_CSI_RS_ResourceId_t csi_id) -{ - bool found = false; - for (int csi_list = 0; csi_list < csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { - NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list]; - if(csires->bwp_Id != dl_bwp_id) - continue; - struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList *resset = &csires->csi_RS_ResourceSetList; - if(resset->present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) - continue; - if(!resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) - continue; - for(int i = 0; i < resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count; i++) { - NR_NZP_CSI_RS_ResourceSetId_t *res_id = resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[i]; - AssertFatal(res_id, "NR_NZP_CSI_RS_ResourceSetId shouldn't be NULL\n"); - struct NR_CSI_MeasConfig__nzp_CSI_RS_ResourceSetToAddModList *res_list = csi_measconfig->nzp_CSI_RS_ResourceSetToAddModList; - AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n"); - for (int j = 0; j < res_list->list.count; j++) { - NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j]; - if (*res_id != csi_res->nzp_CSI_ResourceSetId) - continue; - for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) { - AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n"); - if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) { - found = true; - break; - } - } - if (found && csi_res->trs_Info) - // CRI-RS for Tracking (not implemented yet) - // in this case we there is no associated CSI report - // therefore to signal this we return a value higher than - // maxNrofCSI-ResourceConfigurations - return NR_maxNrofCSI_ResourceConfigurations + 1; - else if (found) - return csires->csi_ResourceConfigId; - } - } - } - return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID -} + LOG_D(NR_MAC, + "PHR Reporting sfn.slot %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n", + frame, + slot, + phr_info->phr_reporting, + phr->PCMAX, + P_CMAX, + phr->PH, + headroom, + tx_power); -uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id) -{ - uint8_t meas_bitmap = 0; - if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations) - return meas_bitmap; // CSI-RS for tracking - for(int i = 0; i < csi_measconfig->csi_ReportConfigToAddModList->list.count; i++) { - NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i]; - if(report_config->resourcesForChannelMeasurement != csi_res_id) - continue; - // bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1 - switch (report_config->reportQuantity.present) { - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: - meas_bitmap += (1 << 1) + (1 << 5); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: - meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - meas_bitmap += (1 << 1) + (1 << 4); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - meas_bitmap += 1; - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4); - break; - default: - AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present); - } - } - return meas_bitmap; -} - -void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - const NR_CSI_RS_ResourceMapping_t *resourceMapping, - uint32_t bwp_size, - uint32_t bwp_start) -{ - // According to last paragraph of TS 38.214 5.2.2.3.1 - if (resourceMapping->freqBand.startingRB < bwp_start) - csirs_config_pdu->start_rb = bwp_start; - else - csirs_config_pdu->start_rb = resourceMapping->freqBand.startingRB; - if (resourceMapping->freqBand.nrofRBs > (bwp_start + bwp_size - csirs_config_pdu->start_rb)) - csirs_config_pdu->nr_of_rbs = bwp_start + bwp_size - csirs_config_pdu->start_rb; - else - csirs_config_pdu->nr_of_rbs = resourceMapping->freqBand.nrofRBs; - AssertFatal(csirs_config_pdu->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_config_pdu->nr_of_rbs); - - csirs_config_pdu->symb_l0 = resourceMapping->firstOFDMSymbolInTimeDomain; - if (resourceMapping->firstOFDMSymbolInTimeDomain2) - csirs_config_pdu->symb_l1 = *resourceMapping->firstOFDMSymbolInTimeDomain2; - csirs_config_pdu->cdm_type = resourceMapping->cdm_Type; - - csirs_config_pdu->freq_density = resourceMapping->density.present; - if ((resourceMapping->density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5) - && (resourceMapping->density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs)) - csirs_config_pdu->freq_density--; - - switch(resourceMapping->frequencyDomainAllocation.present){ - case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1: - csirs_config_pdu->row = 1; - csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f; - break; - case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2: - csirs_config_pdu->row = 2; - csirs_config_pdu->freq_domain = (((resourceMapping->frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f) - | ((resourceMapping->frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0)); - break; - case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4: - csirs_config_pdu->row = 4; - csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07; - break; - case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other: - csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f; - // determining the row of table 7.4.1.5.3-1 in 38.211 - switch (resourceMapping->nrofPorts) { - case NR_CSI_RS_ResourceMapping__nrofPorts_p1: - AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n"); - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p2: - csirs_config_pdu->row = 3; - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p4: - csirs_config_pdu->row = 5; - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p8: - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) - csirs_config_pdu->row = 8; - else { - int num_k = 0; - for (int k = 0; k < 6; k++) - num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01); - if (num_k == 4) - csirs_config_pdu->row = 6; - else - csirs_config_pdu->row = 7; - } - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p12: - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) - csirs_config_pdu->row = 10; - else - csirs_config_pdu->row = 9; - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p16: - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) - csirs_config_pdu->row = 12; - else - csirs_config_pdu->row = 11; - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p24: - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) - csirs_config_pdu->row = 14; - else { - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) - csirs_config_pdu->row = 15; - else - csirs_config_pdu->row = 13; - } - break; - case NR_CSI_RS_ResourceMapping__nrofPorts_p32: - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) - csirs_config_pdu->row = 17; - else { - if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) - csirs_config_pdu->row = 18; - else - csirs_config_pdu->row = 16; - } - break; - default: - AssertFatal(false, "Invalid number of ports in CSI-RS resource\n"); - } - break; - default: - AssertFatal(false, "Invalid freqency domain allocation in CSI-RS resource\n"); - } -} - -static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) -{ - if (!mac->sc_info.csi_MeasConfig) - return; - - NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig; - - if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL) - return; - - fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot); - NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; - NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id; - - int mu = current_DL_BWP->scs; - uint16_t bwp_size = current_DL_BWP->BWPSize; - uint16_t bwp_start = current_DL_BWP->BWPStart; - - for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++) { - NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id]; - int period, offset; - csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset); - if((frame * mac->frame_structure.numb_slots_frame + slot-offset) % period != 0) - continue; - NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId); - // do not schedule reseption of this CSI-RS if not associated with current BWP - if(csi_res_id < 0) - continue; - LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot); - fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csirs_config_pdu.csirs_config_rel15; - csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id); - csirs_config_pdu->subcarrier_spacing = mu; - csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0; - - if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations) - csirs_config_pdu->csi_type = 0; // TRS - else - csirs_config_pdu->csi_type = 1; // NZP-CSI-RS - - csirs_config_pdu->scramb_id = nzpcsi->scramblingID; - csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8; - if (nzpcsi->powerControlOffsetSS) - csirs_config_pdu->power_control_offset_ss = *nzpcsi->powerControlOffsetSS; - else - csirs_config_pdu->power_control_offset_ss = 1; // 0 dB - - configure_csi_resource_mapping(csirs_config_pdu, &nzpcsi->resourceMapping, bwp_size, bwp_start); - - dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS; - dl_config->number_pdus += 1; - } -} - -static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods) -{ - int config_period = prach_occasion_info->frame_info[0]; - int frame_period = config_period * association_periods; - int frame_in_period = frame % frame_period; - if (association_periods > 1) { - int current_assoc_period = frame_in_period / config_period; - if (current_assoc_period != prach_occasion_info->association_period_idx) - return false; - frame_in_period %= config_period; - } - if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211) - return true; - else - return false; -} - -// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x -// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3. -// - todo: -// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config -static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP) -{ - RA_config_t *ra = &mac->ra; - - // Get any valid PRACH occasion in the current slot for the selected SSB index - prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info; - - if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods)) - return; - - if (is_ul_slot(slotP, &mac->frame_structure)) { - if (slotP == prach_occasion_info->slot) { - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH); - if (!pdu) { - LOG_E(NR_MAC, "Error in PRACH allocation\n"); - return; - } - - int format = prach_occasion_info->format; - fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config; - pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){ - .phys_cell_id = mac->physCellId, - .num_prach_ocas = 1, - .prach_slot = prach_occasion_info->slot, - .prach_start_symbol = prach_occasion_info->start_symbol, - .num_ra = prach_occasion_info->fdm, - .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config), - .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index, - .restricted_set = prach_config->restricted_set_config, - .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1}; - - LOG_I(NR_MAC, - "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", - frameP, - pdu->prach_config_pdu.prach_slot, - pdu->prach_config_pdu.prach_start_symbol, - pdu->prach_config_pdu.num_ra); - - switch (format) { // single PRACH format - case 0: - pdu->prach_config_pdu.prach_format = 0; - break; - case 1: - pdu->prach_config_pdu.prach_format = 1; - break; - case 2: - pdu->prach_config_pdu.prach_format = 2; - break; - case 3: - pdu->prach_config_pdu.prach_format = 3; - break; - case 0xa1: - pdu->prach_config_pdu.prach_format = 4; - break; - case 0xa2: - pdu->prach_config_pdu.prach_format = 5; - break; - case 0xa3: - pdu->prach_config_pdu.prach_format = 6; - break; - case 0xb1: - pdu->prach_config_pdu.prach_format = 7; - break; - case 0xb4: - pdu->prach_config_pdu.prach_format = 8; - break; - case 0xc0: - pdu->prach_config_pdu.prach_format = 9; - break; - case 0xc2: - pdu->prach_config_pdu.prach_format = 10; - break; - default: - AssertFatal(false, "Invalid PRACH format"); - } - - pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex; - pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); - release_ul_config(pdu, false); - nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, - .mac = mac, - .module_id = mac->ue_id, - .CC_id = 0 /*TBR fix*/}; - if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) - mac->if_module->scheduled_response(&scheduled_response); - - T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot), - T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power)); - - const int n_slots_frame = mac->frame_structure.numb_slots_frame; - if (ra->ra_type == RA_4_STEP) { - ra->ra_state = nrRA_WAIT_RAR; - // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH - // the response window timer should be started at that time - // but for processing reasons it is better to start it here and to add the slot difference - // that also takes into account the rx to tx slot offset - int next_slot = (slotP + 1) % n_slots_frame; - int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER; - int add_slots = 1; - NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id]; - const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); - while (!is_dl_slot(next_slot, &mac->frame_structure) - || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, ra_SS)) { - int temp_slot = (next_slot + 1) % n_slots_frame; - next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER; - next_slot = temp_slot; - add_slots++; - } - add_slots += GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mac->current_DL_BWP->scs); - nr_timer_setup(&ra->response_window_timer, ra->response_window_setup_time + add_slots, 1); - nr_timer_start(&ra->response_window_timer); - } else if (ra->ra_type == RA_2_STEP) { - NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource = - mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16; - slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame; - frame_t msgA_pusch_frame = - (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024; - - fapi_nr_ul_config_request_pdu_t *pdu = - lockGet_ul_config(mac, msgA_pusch_frame, msgA_pusch_slot, FAPI_NR_UL_CONFIG_TYPE_PUSCH); - if (!pdu) - return; - - // Config Msg3/MsgA-PUSCH PDU - NR_tda_info_t tda_info = {0}; - AssertFatal(msgA_PUSCH_Resource->startSymbolAndLengthMsgA_PO_r16, - "Only SLIV based on startSymbolAndLengthMsgA_PO_r16 implemented\n"); - - int ret = nr_config_pusch_pdu(mac, - &tda_info, - &pdu->pusch_config_pdu, - NULL, - NULL, - NULL, - mac->ra.ra_rnti, - NR_SearchSpace__searchSpaceType_PR_common, - NR_DCI_NONE); - - if (ret != 0) - remove_ul_config_last_item(pdu); - release_ul_config(pdu, false); - - LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]); - ra->ra_state = nrRA_WAIT_MSGB; - ra->t_crnti = 0; - mac->crnti = 0; - ra->ra_rnti = 0; - } else { - AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type); - } - } // is_nr_prach_slot - } // if is_nr_UL_slot + phr_info->PathlossLastValue = compute_nr_SSB_PL(mac); + // Restart both timers according to 38.321 + nr_timer_start(&phr_info->periodicPHR_Timer); + nr_timer_start(&phr_info->prohibitPHR_Timer); + phr_info->phr_reporting = 0; } typedef struct { @@ -2265,6 +1930,44 @@ typedef struct { uint32_t lcp_allocation_counter; } NR_UE_MAC_CE_INFO; +static uint8_t nr_locate_BsrIndexByBufferSize(int size, int value) +{ + if (value == 0) { + return 0; //elseif (value > 150000) return 63; + } + + uint32_t (*get_bsr_value)(int); + if (size == NR_SHORT_BSR_TABLE_SIZE) + get_bsr_value = &get_short_bsr_value; + else + get_bsr_value = &get_long_bsr_value; + + int jl = 0; // lower bound + int ju = size - 1; // upper bound + // determine the order of the the table: 1 if ascending order of table, 0 otherwise + bool ascend = (*get_bsr_value)(ju) >= (*get_bsr_value)(jl) ? 1 : 0; + while (ju - jl > 1) { //If we are not yet done, + int jm = (ju + jl) / 2; // compute a midpoint, + if ((value >= (*get_bsr_value)(jm)) == ascend) { + jl = jm; // replace the lower limit + } else { + ju = jm; //replace the upper limit + } + + LOG_T(NR_MAC, + "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n", + jm, + (*get_bsr_value)(jm), + value); + } + + if (value == (*get_bsr_value)(jl)) { + return jl; + } else { + return jl + 1; //equally ju + } +} + static void nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, @@ -2837,54 +2540,329 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, return mac_ce_info.num_sdus > 0; // success if we got at least one sdu } -static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) +void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) { - NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; - fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu; - ta->ta_frame = ul_time_alignment->frame; - ta->ta_slot = ul_time_alignment->slot; - ta->is_rar = ul_time_alignment->ta_apply == rar_ta; - ta->ta_command = ul_time_alignment->ta_command; - dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND; - dl_config->number_pdus += 1; - ul_time_alignment->ta_apply = no_ta; -} + int cc_id = ul_info->cc_id; + frame_t frame_tx = ul_info->frame; + slot_t slot_tx = ul_info->slot; + uint32_t gNB_index = ul_info->gNB_index; -static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, - NR_SINGLE_ENTRY_PHR_MAC_CE *phr, - float P_CMAX, - float tx_power, - frame_t frame, - slot_t slot) -{ - nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info; - // Value mapping according to 38.133 10.1.18.1 - const int PC_MAX_00 = -29; - *phr = (NR_SINGLE_ENTRY_PHR_MAC_CE){.PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f}; - // Value mapping according to 38.133 10.1.17.1.1 - const int POWER_HEADROOM_55 = 22; - int headroom = P_CMAX - tx_power; - if (headroom < POWER_HEADROOM_55) { - const int POWER_HEADROOM_0 = -32; - phr->PH = max(0, headroom - POWER_HEADROOM_0); - } else { - phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2); + RA_config_t *ra = &mac->ra; + + if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) { + init_RA(mac, frame_tx); + // perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a) + ra_resource_selection(mac); } - LOG_D(NR_MAC, - "PHR Reporting sfn.slot %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n", - frame, - slot, - phr_info->phr_reporting, - phr->PCMAX, - P_CMAX, - phr->PH, - headroom, - tx_power); + if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE) + nr_ue_prach_scheduler(mac, frame_tx, slot_tx); - phr_info->PathlossLastValue = compute_nr_SSB_PL(mac); - // Restart both timers according to 38.321 - nr_timer_start(&phr_info->periodicPHR_Timer); - nr_timer_start(&phr_info->prohibitPHR_Timer); - phr_info->phr_reporting = 0; + bool BSRsent = false; + if (mac->state == UE_CONNECTED) { + nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx); + nr_update_rlc_buffers_status(mac, frame_tx, slot_tx, gNB_index); + } + + // Schedule ULSCH only if the current frame and slot match those in ul_config_req + // AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus) + uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES]; + int number_of_pdus = 0; + + fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx); + if (!ulcfg_pdu) + return; + LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx); + + while (ulcfg_pdu->pdu_type != FAPI_NR_END) { + uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus]; + if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) { + nfapi_nr_ue_pusch_pdu_t *pdu = &ulcfg_pdu->pusch_config_pdu; + uint32_t TBS_bytes = pdu->pusch_data.tb_size; + LOG_D(NR_MAC, + "harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n", + pdu->pusch_data.harq_process_id, + pdu->pusch_data.new_data_indicator, + TBS_bytes, + ra->ra_state); + pdu->tx_request_body.fapiTxPdu = NULL; + if ((ra->ra_state == nrRA_WAIT_RAR || ra->ra_state == nrRA_WAIT_MSGB) && !ra->cfra) { + nr_get_Msg3_MsgA_PUSCH_payload(mac, ulsch_input_buffer, TBS_bytes); + for (int k = 0; k < TBS_bytes; k++) { + LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]); + } + pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer; + pdu->tx_request_body.pdu_length = TBS_bytes; + number_of_pdus++; + T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx), + T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes)); + } else { + if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator + && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) { + if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { + // UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" + trigger_MAC_UE_RA(mac, NULL); + return; + } + // Getting IP traffic to be transmitted + int tx_power = pdu->tx_power; + int P_CMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frame_structure.frame_type, + mac->frequency_range, + mac->current_UL_BWP->channel_bandwidth, + pdu->qam_mod_order, + false, + mac->current_UL_BWP->scs, + mac->current_UL_BWP->BWPSize, + pdu->transform_precoding, + pdu->rb_size, + pdu->rb_start); + + nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes, tx_power, P_CMAX, &BSRsent); + pdu->tx_request_body.fapiTxPdu = ulsch_input_buffer; + pdu->tx_request_body.pdu_length = TBS_bytes; + number_of_pdus++; + T(T_NRUE_MAC_UL_PDU_WITH_DATA, T_INT(mac->crnti), T_INT(frame_tx), T_INT(slot_tx), + T_INT(ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id), T_BUFFER(ulsch_input_buffer, TBS_bytes)); + // start or restart dataInactivityTimer if any MAC entity transmits a MAC SDU for DTCH logical channel, + // or DCCH logical channel + if (mac->data_inactivity_timer) + nr_timer_start(mac->data_inactivity_timer); + } + } + + if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) { + LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx); + // 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3 + // transmission + nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index); + } + if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) { + LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx); + nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index); + } + if (ra->ra_state == nrRA_WAIT_MSGB && !ra->cfra) { + LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-MsgA-PUSCH transmitted\n", frame_tx, slot_tx); + } + } + ulcfg_pdu++; + } + release_ul_config(ulcfg_pdu, false); + + if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING) + nr_ue_pucch_scheduler(mac, frame_tx, slot_tx); + + if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) { + LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx); + nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx, + .mac = mac, + .module_id = mac->ue_id, + .CC_id = cc_id, + .phy_data = ul_info->phy_data}; + mac->if_module->scheduled_response(&scheduled_response); + } + + if(mac->state == UE_CONNECTED) + nr_update_sr(mac, BSRsent); + // Global variables implicit logic + // far away, BSR_reporting_active is set + mac->scheduling_info.BSR_reporting_active = NR_BSR_TRIGGER_NONE; + + // update Bj for all active lcids before LCP procedure + if (mac->current_UL_BWP) { + LOG_D(NR_MAC, "%4d.%2d Logical Channel Prioritization\n", frame_tx, slot_tx); + for (int i = 0; i < mac->lc_ordered_list.count; i++) { + nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + int lcid = lc_info->lcid; + // max amount of data that can be buffered/accumulated in a logical channel buffer + uint32_t bucketSize_max = lc_info->bucket_size; + // measure Bj increment the value of Bj by product PBR * T + NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); + int32_t bj = sched_info->Bj; + if (lc_info->pbr < UINT_MAX) { + uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented + // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s + uint32_t pbr_ms = lc_info->pbr / 1000; + bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms + } + else + bj = INT_MAX; + // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization + sched_info->Bj = min(bj, bucketSize_max); + // reset bj timer + nr_timer_start(&sched_info->Bj_timer); + } + } +} + +// PUSCH scheduler: +// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, +// - where K2 is the offset between the slot in which UL DCI is received and the slot +// - in which ULSCH should be scheduled. K2 is configured in RRC configuration. +// PUSCH Msg3 scheduler: +// - scheduled by RAR UL grant according to 8.3 of TS 38.213 +// Note: Msg3 tx in the uplink symbols of mixed slot +int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, + const uint8_t is_Msg3, + const frame_t current_frame, + const int current_slot, + frame_t *frame_tx, + int *slot_tx, + const long k2) +{ + int delta = 0; + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + + // Get the numerology to calculate the Tx frame and slot + int mu = current_UL_BWP->scs; + int slots_per_frame = mac->frame_structure.numb_slots_frame; + + // k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1 + // PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon + + if (is_Msg3) { + + delta = get_delta_for_k2(mu); + + AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to " + "%ld in gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", + k2, + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu)); + + + *slot_tx = (current_slot + k2 + delta) % slots_per_frame; + *frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER; + } else { + AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in " + "gNB config file or gNBs.[0].min_rxtxtime=%ld via command line.\n", + k2, + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu), + GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu)); + + + if (k2 < 0) { // This can happen when a false DCI is received + LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2); + return -1; + } + + // Calculate TX slot and frame + *slot_tx = (current_slot + k2) % slots_per_frame; + *frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER; + } + + LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta); + return 0; +} + +void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, + const NR_CSI_RS_ResourceMapping_t *resourceMapping, + uint32_t bwp_size, + uint32_t bwp_start) +{ + // According to last paragraph of TS 38.214 5.2.2.3.1 + if (resourceMapping->freqBand.startingRB < bwp_start) + csirs_config_pdu->start_rb = bwp_start; + else + csirs_config_pdu->start_rb = resourceMapping->freqBand.startingRB; + if (resourceMapping->freqBand.nrofRBs > (bwp_start + bwp_size - csirs_config_pdu->start_rb)) + csirs_config_pdu->nr_of_rbs = bwp_start + bwp_size - csirs_config_pdu->start_rb; + else + csirs_config_pdu->nr_of_rbs = resourceMapping->freqBand.nrofRBs; + AssertFatal(csirs_config_pdu->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_config_pdu->nr_of_rbs); + + csirs_config_pdu->symb_l0 = resourceMapping->firstOFDMSymbolInTimeDomain; + if (resourceMapping->firstOFDMSymbolInTimeDomain2) + csirs_config_pdu->symb_l1 = *resourceMapping->firstOFDMSymbolInTimeDomain2; + csirs_config_pdu->cdm_type = resourceMapping->cdm_Type; + + csirs_config_pdu->freq_density = resourceMapping->density.present; + if ((resourceMapping->density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5) + && (resourceMapping->density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs)) + csirs_config_pdu->freq_density--; + + switch(resourceMapping->frequencyDomainAllocation.present){ + case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1: + csirs_config_pdu->row = 1; + csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f; + break; + case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2: + csirs_config_pdu->row = 2; + csirs_config_pdu->freq_domain = (((resourceMapping->frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f) + | ((resourceMapping->frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0)); + break; + case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4: + csirs_config_pdu->row = 4; + csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07; + break; + case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other: + csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f; + // determining the row of table 7.4.1.5.3-1 in 38.211 + switch (resourceMapping->nrofPorts) { + case NR_CSI_RS_ResourceMapping__nrofPorts_p1: + AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n"); + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p2: + csirs_config_pdu->row = 3; + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p4: + csirs_config_pdu->row = 5; + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p8: + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) + csirs_config_pdu->row = 8; + else { + int num_k = 0; + for (int k = 0; k < 6; k++) + num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01); + if (num_k == 4) + csirs_config_pdu->row = 6; + else + csirs_config_pdu->row = 7; + } + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p12: + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) + csirs_config_pdu->row = 10; + else + csirs_config_pdu->row = 9; + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p16: + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) + csirs_config_pdu->row = 12; + else + csirs_config_pdu->row = 11; + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p24: + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) + csirs_config_pdu->row = 14; + else { + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) + csirs_config_pdu->row = 15; + else + csirs_config_pdu->row = 13; + } + break; + case NR_CSI_RS_ResourceMapping__nrofPorts_p32: + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2) + csirs_config_pdu->row = 17; + else { + if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4) + csirs_config_pdu->row = 18; + else + csirs_config_pdu->row = 16; + } + break; + default: + AssertFatal(false, "Invalid number of ports in CSI-RS resource\n"); + } + break; + default: + AssertFatal(false, "Invalid freqency domain allocation in CSI-RS resource\n"); + } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index dd5558d546..6dd4886911 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -490,16 +490,16 @@ static bool check_sib1_tda(gNB_MAC_INST *gNB_mac, // the UE may assume that this PDSCH resource allocation is not applied (Table 5.1.2.1.1-4 and 5 in 38.214) int row = tda + 1; if (table_type == defaultB && (row == 12 || row == 13 || row == 14)) - false; + return false; if (table_type == defaultC && (row == 1 || row == 6 || row == 7 ||row > 12)) - false; + return false; // assuming normal CP NR_tda_info_t tda_info = get_info_from_tda_tables(table_type, tda, scc->dmrs_TypeA_Position, true); // SIB1 TDA going to the last symbol would cause overlap with CSI-RS if (!tda_info.valid_tda || tda_info.startSymbolIndex + tda_info.nrOfSymbols == 14) - false; + return false; if (tda_info.startSymbolIndex < type0_PDCCH_CSS_config->first_symbol_index + type0_PDCCH_CSS_config->num_symbols) - false; + return false; NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, NULL, &tda_info, 1); // Configure sched_ctrlCommon for SIB1 diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4d28d66b69..3b8476f9a4 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1092,7 +1092,13 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(du); LOG_I(NR_RRC, "Reestablishment update key pci=%d, earfcn_dl=%u\n", cell_info->nr_pci, ssb_arfcn); - nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc > 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb); + + /* Per TS 33.501 6.9.2.3.4: When sending RRCReestablishment with nextHopChainingCount, + * we're staying at the same NCC level (not advancing), so use horizontal derivation + * from the currently active KgNB. Vertical derivation (from NH) is only used when + * advancing to a new NCC level, which happens during handover or masterKeyUpdate. */ + const uint8_t *base_key = ue_p->kgnb; + nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, base_key, ue_p->kgnb); int size = do_RRCReestablishment(ue_context_pP->ue_context.nh_ncc, buffer, NR_RRC_BUF_SIZE, xid); LOG_A(NR_RRC, "Send RRCReestablishment [%d bytes] to RNTI %04x\n", size, ue_p->rnti); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 5c212438e1..65991f714d 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1649,7 +1649,7 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc, msg.source2target->ue_history_info.cause->type = NGAP_CAUSE_RADIO_NETWORK; msg.source2target->ue_history_info.cause->value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON; msg.source2target->ue_history_info.type = NGAP_CellSize_small; - msg.source2target->ue_history_info.time_in_cell = 500; // dummy number for now + msg.source2target->ue_history_info.time_in_cell = min(time(NULL) - UE->last_seen, 4095); msg.source2target->ue_history_info.id = target_cell; /* Fill both PDU Session Resource List IE (M) in Handover Required diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 384be2a7b1..424118fa4c 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -527,13 +527,141 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } -static void nr_rrc_nh_update(NR_UE_RRC_INST_t *rrc, uint8_t *kamf, uint8_t *sync_input) +/** @brief Synchronize NH chain based on nextHopChainingCount + * + * This function synchronizes the NH parameter chain as specified in 3GPP TS 33.501 Annex A.10. + * Use cases: Master Key Update, RRC Reestablishment: The UE receives an NCC value that is + * different from the NCC associated with the currently active KgNB. The NH chain is synchronized + * by computing the function defined in Annex A.10 iteratively (and increasing the NCC value until + * it matches the NCC value received from the source ng-gNB). + * + * @param kamf K_AMF key from NAS + * @param kgnb Current KgNB key (input/output) + * @param nh Current NH parameter (input/output) + * @param nhcc Pointer to current nextHopChainingCount (input/output) + * @param target_ncc Target nextHopChainingCount value to synchronize to */ +static void nr_sync_nh_chain(const uint8_t kamf[SECURITY_KEY_LEN], + uint8_t kgnb[SECURITY_KEY_LEN], + uint8_t nh[SECURITY_KEY_LEN], + uint64_t *nhcc, + const int8_t target_ncc) { - uint8_t nh[SECURITY_KEY_LEN] = {0}; - nr_derive_nh(kamf, sync_input, nh); - log_hex_buffer("Sync input = stored NH", rrc->nh, SECURITY_KEY_LEN); - memcpy(rrc->nh, nh, SECURITY_KEY_LEN); - rrc->nhcc++; // Increase stored nextHopChainingCount + // If the UE received an NCC value that was different from the NCC associated with the + // currently active KgNB, the UE shall first synchronize the locally kept NH + // parameter by computing the function defined in Annex A.10 iteratively (and increasing + // the NCC value until it matches the NCC value received from the source ng-gNB). + if (target_ncc <= *nhcc) { + LOG_W(NR_RRC, "Received NCC=%d is less than or equal to current nhcc=%ld (nothing to sync)\n", target_ncc, *nhcc); + return; + } + if (target_ncc > *nhcc) { + LOG_I(NR_RRC, "Synchronizing NH chain: current nhcc=%ld, target ncc=%d\n", *nhcc, target_ncc); + if (*nhcc == 0) { + // First derivation: derive KgNB from KAMF, then derive NH from KgNB (per TS 33.501 A.10) + // Note: For the first NH derivation, we use UL NAS COUNT = 0 to match the AMF's derivation + // during handover. The AMF derives the first NH using the UL NAS COUNT from the last + // successful NAS SMC, which is 0 for the initial derivation. + derive_kgnb(kamf, 0, kgnb); + nr_derive_nh(kamf, kgnb, nh); + *nhcc = 1; + } + // Following derivations: iterate from current nhcc to target_ncc + for (uint8_t i = *nhcc; i < target_ncc; i++) { + LOG_D(NR_RRC, "Derive keys for ChainingCount = %d\n", i); + nr_derive_nh(kamf, nh, nh); + } + *nhcc = target_ncc; + } +} + +/** @brief Derive KNG-RAN* (KgNB*) using horizontal derivation + * + * This function derives KNG-RAN* from the currently active KgNB (horizontal derivation) + * as specified in 3GPP TS 33.501 Annex A.11 and A.12. + * Used when NCC values match (no NH synchronization needed). + * + * @param pci Physical Cell ID + * @param nr_arfcn_dl NR ARFCN-DL + * @param kgnb Current KgNB key (input/output) + */ +static void nr_derive_kgnb_horizontal(const uint16_t pci, const uint64_t nr_arfcn_dl, uint8_t kgnb[SECURITY_KEY_LEN]) +{ + // When the NCC values match, the UE shall derive the KNG-RAN* from the currently active + // KgNB and the target PCI and its frequency ARFCN-DL using the function defined in Annex A.11 and A.12. + LOG_D(NR_RRC, "Deriving KNG-RAN* using horizontal derivation (from current KgNB)\n"); + nr_derive_key_ng_ran_star(pci, nr_arfcn_dl, kgnb, kgnb); +} + +/** @brief Derive KNG-RAN* (KgNB*) using vertical derivation + * + * This function derives KNG-RAN* from the synchronized NH parameter (vertical derivation) + * as specified in 3GPP TS 33.501 Annex A.11 and A.12. + * Used after NH chain synchronization when NCC values differ. + * + * @param pci Physical Cell ID + * @param nr_arfcn_dl NR ARFCN-DL + * @param kgnb Current KgNB key (input/output) + * @param nh Synchronized NH parameter (input) + */ +static void nr_derive_kgnb_vertical(const uint16_t pci, + const uint64_t nr_arfcn_dl, + uint8_t kgnb[SECURITY_KEY_LEN], + const uint8_t nh[SECURITY_KEY_LEN]) +{ + // When the NCC values match (after synchronization), the UE shall compute the K NG-RAN * + // from the synchronized NH parameter and the target PCI and its frequency ARFCN-DL + // using the function defined in Annex A.11 and A.12. + LOG_D(NR_RRC, "Deriving KNG-RAN* using vertical derivation (from synchronized NH)\n"); + nr_derive_key_ng_ran_star(pci, nr_arfcn_dl, nh, kgnb); +} + +/** @brief Update KgNB based on received nextHopChainingCount + * + * This function implements the common logic for updating KgNB based on received NCC value, + * as specified in 3GPP TS 33.501 6.9.2.3.4. + * + * Per 33.501 6.9.2.3.4 and Fig 6.9.2.1.1-1: + * - If NCC received == current NCC: use horizontal derivation (from currently active KgNB) + * This applies regardless of whether NCC is 0 or >0. For a fixed NCC level, multiple + * horizontal derivations can be done within that level. + * - If NCC received > current NCC: synchronize NH chain (Annex A.10), then use vertical + * derivation (from NH) to enter the new NCC level. + * + * Horizontal derivation = derive KNG-RAN* from currently active KgNB + (PCI, ARFCN-DL) + * Vertical derivation = derive KNG-RAN* from NH + (PCI, ARFCN-DL) + * + * @param rrc RRC instance pointer + * @param kamf K_AMF key from NAS + * @param received_ncc Received nextHopChainingCount value */ +static void nr_update_kgnb_from_ncc(NR_UE_RRC_INST_t *rrc, const uint8_t kamf[SECURITY_KEY_LEN], int8_t received_ncc) +{ + const uint64_t original_nhcc = rrc->nhcc; + + if (received_ncc == original_nhcc) { + // NCC values match: use horizontal derivation from currently active KgNB + // Per TS 33.501 6.9.2.3.4: "derive the KNG-RAN* from the currently active KgNB" + // This applies regardless of NCC being 0 or >0. For a fixed NCC level, we stay + // within that level using horizontal derivations. + LOG_D(NR_RRC, "NCC values match (%d), using horizontal derivation\n", received_ncc); + nr_derive_kgnb_horizontal(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb); + } else if (received_ncc < original_nhcc) { + // Note: According to spec, NCC should only increase. If received_ncc < original_nhcc, + // this is an error condition, but we handle it gracefully. + LOG_W(NR_RRC, + "Received NCC=%d is less than current nhcc=%ld (unexpected per spec, NH chain should only increase)\n", + received_ncc, + original_nhcc); + } else { + // received_ncc > original_nhcc: synchronize NH chain first (per 33.501 A.10) + nr_sync_nh_chain(kamf, rrc->kgnb, rrc->nh, &rrc->nhcc, received_ncc); + // Store the received nextHopChainingCount value (per 38.331 5.3.7.5) + LOG_D(NR_RRC, "Synchronizing NH chain to target NCC %d\n", received_ncc); + rrc->nhcc = received_ncc; + // After synchronization, derive KNG-RAN* from synchronized NH (vertical derivation) + // per 33.501 6.9.2.3.4: "When the NCC values match, the UE shall compute the K NG-RAN * + // from the synchronized NH parameter" + nr_derive_kgnb_vertical(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->nh); + } } /** @brief AS security key update procedure (5.3.5.7 3GPP TS 38.331) */ @@ -545,40 +673,17 @@ void as_security_key_update(NR_UE_RRC_INST_t *rrc, NR_MasterKeyUpdate_t *mku) if (mku->keySetChangeIndicator) { LOG_E(NR_RRC, "derive or update the K gNB key based on the K AMF key, as specified in TS 33.501: not implemented yet\n"); } else { - /* derive or update the K gNB key based on the current K gNB key or the NH, using the nextHopChainingCount - value indicated in the received masterKeyUpdate, as specified in 6.9.2.3.3 3GPP TS 33.501 */ - if (mku->nextHopChainingCount != rrc->nhcc) { - // - If the UE received an NCC value that was different from the NCC associated with the currently active - // K gNB/K eNB, the UE shall first synchronize the locally kept NH parameter by computing the function defined in - // Annex A.10 iteratively (and increasing the NCC value until it matches the NCC value received from the source - // ng-eNB/gNB via the HO command message. - LOG_A(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount); - /** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized - * with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig - * processing that triggers bearer modifications. Security configueration of bearers must - * complete using the newly derived keys. As a workaround NAS is directly accessed here. */ - nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id); - uint8_t *kamf = nas->security.kamf; - log_hex_buffer("Stored kamf", kamf, SECURITY_KEY_LEN); - if (rrc->nhcc == 0) { // First derivation - derive_kgnb(kamf, 0, rrc->kgnb); - log_hex_buffer("Sync input = derived kgnb", rrc->kgnb, SECURITY_KEY_LEN); - nr_rrc_nh_update(rrc, kamf, rrc->kgnb); - } - for (int i = rrc->nhcc; i < mku->nextHopChainingCount; i++) { // Following derivations - LOG_D(NR_RRC, "Derive keys for ChainingCount = %d\n", i); - nr_rrc_nh_update(rrc, kamf, rrc->nh); - } - nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->nh, rrc->kgnb); - // When the NCC values match, the UE shall compute the K NG-RAN * - // from the synchronized NH parameter and the target PCI and its frequency ARFCN-DL/EARFCN-DL using the - // function defined in Annex A.11 and A.12. - // The UE shall use the KNG-RAN * as the K gNB when communicating with the target gNB and as the KeNB when - // communicating with the target ng-eNB. - } else { - nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb); - } - log_hex_buffer("Derived kgnb", rrc->kgnb, SECURITY_KEY_LEN); + LOG_I(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount); + /** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized + * with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig + * processing that triggers bearer modifications. Security configueration of bearers must + * complete using the newly derived keys. As a workaround NAS is directly accessed here. */ + nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id); + const uint8_t *kamf = nas->security.kamf; + // KgNB update (TS 33.501 ยง6.9.2.3.3): + // If received NCC != local NCC, iteratively derive NH (Annex A.10) until NCC matches. + // Then derive the new KgNB from the synchronized NH. + nr_update_kgnb_from_ncc(rrc, kamf, mku->nextHopChainingCount); } } @@ -2246,6 +2351,9 @@ static void nr_rrc_ue_generate_rrcReestablishmentComplete(const NR_UE_RRC_INST_t nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); } +/** @brief Process RRCReestablishment message + * This function processes the RRCReestablishment message received from the gNB, + * implementing procedures as described in 38.331 section 5.3.7.5 */ static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc, const int gNB_index, const NR_RRCReestablishment_t *rrcReestablishment, @@ -2254,18 +2362,19 @@ static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc, int msg_size, const nr_pdcp_integrity_data_t *msg_integrity) { - // implementign procedues as described in 38.331 section 5.3.7.5 // stop timer T301 NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; nr_timer_stop(&timers->T301); - // store the nextHopChainingCount value NR_RRCReestablishment_IEs_t *ies = rrcReestablishment->criticalExtensions.choice.rrcReestablishment; AssertFatal(ies, "Not expecting RRCReestablishment_IEs to be NULL\n"); - // TODO need to understand how to use nextHopChainingCount - // int nh = rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount; - // update the K gNB key based on the current K gNB key or the NH, using the stored nextHopChainingCount value - nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb); + // Update KgNB based on the current K gNB key or the NH, + // using the received nextHopChainingCount (per 33.501 6.9.2.3.4) + // received from RRCReestablishment and update the stored value in rrc->nhcc + int8_t received_ncc = ies->nextHopChainingCount; + nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id); + const uint8_t *kamf = nas->security.kamf; + nr_update_kgnb_from_ncc(rrc, kamf, received_ncc); // derive the K_RRCenc key associated with the previously configured cipheringAlgorithm // derive the K_RRCint key associated with the previously configured integrityProtAlgorithm diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 3fb35adee2..a2948ab0b2 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -150,8 +150,23 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t * NOTE: knas is dynamically allocated by the KDF function */ -/** @brief KgNB derivation (A.9 3GPP TS 33.501) */ -void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) +/** @brief KgNB derivation function (Annex A.9 3GPP TS 33.501) + * + * Derives KgNB from K_AMF and the uplink NAS COUNT. + * This function is applied when cryptographically protected 5G radio bearers are + * established and when a key change on-the-fly is performed. + * + * KDF input S structure (per Annex A.9): + * - FC = 0x6E + * - P0 = Uplink NAS COUNT (count parameter) + * - L0 = length of uplink NAS COUNT (0x00 0x04) + * - P1 = Access type distinguisher (0x01 for 3GPP access) + * - L1 = length of Access type distinguisher (0x00 0x01) + * + * @param[in] kamf 256-bit K_AMF key (input key KEY to KDF) + * @param[in] count Uplink NAS COUNT value (P0 in KDF input S) + * @param[out] kgnb Derived 256-bit KgNB key */ +void derive_kgnb(const uint8_t kamf[32], const uint32_t count, uint8_t *kgnb) { /* Compute the KDF input parameter * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index eff72c68bb..100d554aa2 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -16,7 +16,7 @@ typedef enum { UP_INT_ALG = 0x06 } algorithm_type_dist_t; -void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb); +void derive_kgnb(const uint8_t kamf[32], const uint32_t count, uint8_t *kgnb); void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB); diff --git a/radio/BLADERF/bladerf_lib.c b/radio/BLADERF/bladerf_lib.c index 178fc2fff2..bff12bee8e 100644 --- a/radio/BLADERF/bladerf_lib.c +++ b/radio/BLADERF/bladerf_lib.c @@ -957,8 +957,6 @@ int device_init(openair0_device *device, /* device specific */ //openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered //openair0_cfg->txlaunch_wait_slotcount = 1; //manage when TX processing is triggered - openair0_cfg->iq_txshift = 0;// shift - openair0_cfg->iq_rxrescale = 15;//rescale iqs // init required params switch ((int)openair0_cfg->sample_rate) { @@ -983,8 +981,6 @@ int device_init(openair0_device *device, exit(-1); break; } - openair0_cfg->iq_txshift= 0; - openair0_cfg->iq_rxrescale = 15; /*not sure*/ openair0_cfg->rx_gain_calib_table = calib_table_fx4; // The number of buffers to use in the underlying data stream diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index 5812e63aa4..5877506ea2 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -276,10 +276,6 @@ typedef struct openair0_config { char *sdr_addrs; //! Auto calibration flag int autocal[8]; - //! rf devices work with x bits iqs when oai have its own iq format - //! the two following parameters are used to convert iqs - int iq_txshift; - int iq_rxrescale; //! Configuration file for LMS7002M char *configFilename; //! remote IP/MAC addr for Ethernet interface diff --git a/radio/ETHERNET/ethernet_lib.c b/radio/ETHERNET/ethernet_lib.c index 2a4d021afc..038246c998 100644 --- a/radio/ETHERNET/ethernet_lib.c +++ b/radio/ETHERNET/ethernet_lib.c @@ -540,40 +540,6 @@ int transport_init(openair0_device *device, eth->if_name = eth_params->local_if_name; device->priv = eth; - - - /* device specific */ - // openair0_cfg[0].iq_rxrescale = 15;//rescale iqs - // openair0_cfg[0].iq_txshift = eth_params->iq_txshift;// shift - // openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance; - - /* RRU does not have any information to make this configuration atm */ - /* - if (device->host_type == RAU_HOST) { - - switch ((int)openair0_cfg[0].sample_rate) { - case 30720000: - openair0_cfg[0].samples_per_packet = 3840; - break; - case 23040000: - openair0_cfg[0].samples_per_packet = 2880; - break; - case 15360000: - openair0_cfg[0].samples_per_packet = 1920; - break; - case 7680000: - openair0_cfg[0].samples_per_packet = 960; - break; - case 1920000: - openair0_cfg[0].samples_per_packet = 240; - break; - default: - printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate); - exit(-1); - break; - } - }*/ - device->openair0_cfg=&openair0_cfg[0]; return 0; } diff --git a/radio/USRP/usrp_lib.cpp b/radio/USRP/usrp_lib.cpp index 923e938869..dabc6f8947 100644 --- a/radio/USRP/usrp_lib.cpp +++ b/radio/USRP/usrp_lib.cpp @@ -478,14 +478,15 @@ static int trx_usrp_write(openair0_device *device, nsamps2 = (nsamps+7)>>3; simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2]; - // bring RX data into 12 LSBs for softmodem RX + // bring TX data into 16 MSBs, assuming it is on the 12 LSB after OAI computation + const int shift = 4; for (int i = 0; i < cc; i++) { for (int j = 0; j < nsamps2; j++) { if ((((uintptr_t)buff[i]) & 0x1F) == 0) { - buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], 4); + buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], shift); } else { simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j); - buff_tx[i][j] = simde_mm256_slli_epi16(tmp, 4); + buff_tx[i][j] = simde_mm256_slli_epi16(tmp, shift); } } } @@ -605,17 +606,17 @@ void *trx_usrp_write_thread(void * arg){ nsamps2 = (nsamps+7)>>3; simde__m256i buff_tx[cc < 2 ? 2 : cc][nsamps2]; - - // bring RX data into 12 LSBs for softmodem RX + // bring TX data into 16 MSBs, assuming it is on the 12 LSB after OAI computation + const int shift = 4; for (int i = 0; i < cc; i++) { for (int j = 0; j < nsamps2; j++) { if ((((uintptr_t) buff[i])&0x1F)==0) { - buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], 4); + buff_tx[i][j] = simde_mm256_slli_epi16(((simde__m256i *)buff[i])[j], shift); } else { simde__m256i tmp = simde_mm256_loadu_si256(((simde__m256i *)buff[i]) + j); - buff_tx[i][j] = simde_mm256_slli_epi16(tmp,4); + buff_tx[i][j] = simde_mm256_slli_epi16(tmp, shift); } } } @@ -752,11 +753,13 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp // bring RX data into 12 LSBs for softmodem RX for (int i=0; iru_conf; int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; @@ -190,7 +193,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot); return -1; } - for (sym_idx = 0; sym_idx < prach_info.N_dur; sym_idx++) { + for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { for (int aa = 0; aa < ru->nb_rx; aa++) { int16_t *dst, *src; int idx = 0; @@ -200,7 +203,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData; /* convert Network order to host order */ if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { - if (sym_idx == 0) { + if (sym_idx == prach_start_sym) { for (idx = 0; idx < 139 * 2; idx++) { dst[idx] = ((int16_t)ntohs(src[idx + g_kbar])); } @@ -233,7 +236,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) AssertFatal(1 == 0, "BFP decompression not supported on this architecture"); #endif // note: this is hardwired for 139 point PRACH sequence, kbar=2 - if (sym_idx == 0) // + if (sym_idx == prach_start_sym) for (idx = 0; idx < (139 * 2); idx++) dst[idx] = local_dst[idx + g_kbar]; else diff --git a/radio/rfsimulator/simulator.cpp b/radio/rfsimulator/simulator.cpp index a29001e0bf..65e32216c4 100644 --- a/radio/rfsimulator/simulator.cpp +++ b/radio/rfsimulator/simulator.cpp @@ -54,6 +54,10 @@ extern "C" { #include #include #include "rfsimulator.h" +extern int get_currentchannels_type(const char *buf, + int debug, + webdatadef_t *tdata, + telnet_printfunc_t prnt); // in random_channel.c } #include #include @@ -112,10 +116,6 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole; }; // clang-format on static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt); -extern int get_currentchannels_type(const char *buf, - int debug, - webdatadef_t *tdata, - telnet_printfunc_t prnt); // in random_channel.c static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); diff --git a/radio/rfsimulator/stored_node.c b/radio/rfsimulator/stored_node.c index 51db5bfea1..5792304671 100644 --- a/radio/rfsimulator/stored_node.c +++ b/radio/rfsimulator/stored_node.c @@ -177,6 +177,7 @@ int main(int argc, char *argv[]) { timestamp+=blockSize; header.option_value=0; header.option_flag=0; + header.beam_map = 1; } else { AssertFatal(read(fd,&header,sizeof(header)), ""); }